C#: CancellationToken 不取消阻塞方法
C#: CancellationToken doesn't cancel blocking method
.NET 4.5.1:看来,我无法使用 CancellationTokenSource 内置超时取消任务中的阻塞方法 运行。
class Program
{
static void Main(string[] args)
{
var cts = new System.Threading.CancellationTokenSource();
System.Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
};
MainAsync(args, cts.Token).Wait();
}
// MainAsync from
static async Task MainAsync(string[] args, System.Threading.CancellationToken token)
{
Console.WriteLine("Starting MainAsync");
var cts = new System.Threading.CancellationTokenSource(3000);
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting task...");
var t = new System.Net.Sockets.TcpClient();
var buffer = new byte[t.ReceiveBufferSize];
t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337));
Console.WriteLine("Recieving...");
t.Client.Receive(buffer);
Console.WriteLine("Finished Recieving...");
return true;
}, cts.Token);
var success = await task;
Console.WriteLine("Did the task complete succesfuly?", success);
}
}
上述简短、自包含、正确示例(我希望它是正确的)的输出是:
Starting MainAsync
Starting task...
Recieving...
为什么任务没有取消,没有抛出异常?
正如我在博客中所述,"You keep using that CancellationToken
there. I do not think it means what you think it means."
特别是传给StartNew
的CancellationToken
只会取消委托的starting。如果您希望委托本身支持取消,那么委托本身将不得不遵守 CancellationToken
.
我不确定,但我猜你混淆了“请求取消”与“终止或中止 thread/task”。
这是两个完全不同的东西。根据有关 Canellation in Managerd Threads 的描述,所提供的功能使您能够发送信号之类的东西,表明正在进行的操作应停止。
作为程序员,您如何以及是否对该信号做出反应取决于您。
在您的示例中,您已经开始了一项新任务
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting task...");
var t = new System.Net.Sockets.TcpClient();
var buffer = new byte[t.ReceiveBufferSize];
t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337));
Console.WriteLine("Recieving...");
t.Client.Receive(buffer);
Console.WriteLine("Finished Recieving...");
return true;
}, cts.Token);
不处理取消也不适合这样做。
取消将被使用,例如如果您想跳出多次迭代的循环 - 因此您需要在每次迭代中检查 CancellationToken.IsCancellationRequested
是否已设置为真。
如果是这样,您可以做出相应的反应。
你想要的是中止当前任务背后的线程,在我看来,只有为自己创建 Thread
class 的新实例并相应地处理中止才有可能。
.NET 4.5.1:看来,我无法使用 CancellationTokenSource 内置超时取消任务中的阻塞方法 运行。
class Program
{
static void Main(string[] args)
{
var cts = new System.Threading.CancellationTokenSource();
System.Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
};
MainAsync(args, cts.Token).Wait();
}
// MainAsync from
static async Task MainAsync(string[] args, System.Threading.CancellationToken token)
{
Console.WriteLine("Starting MainAsync");
var cts = new System.Threading.CancellationTokenSource(3000);
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting task...");
var t = new System.Net.Sockets.TcpClient();
var buffer = new byte[t.ReceiveBufferSize];
t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337));
Console.WriteLine("Recieving...");
t.Client.Receive(buffer);
Console.WriteLine("Finished Recieving...");
return true;
}, cts.Token);
var success = await task;
Console.WriteLine("Did the task complete succesfuly?", success);
}
}
上述简短、自包含、正确示例(我希望它是正确的)的输出是:
Starting MainAsync
Starting task...
Recieving...
为什么任务没有取消,没有抛出异常?
正如我在博客中所述,"You keep using that CancellationToken
there. I do not think it means what you think it means."
特别是传给StartNew
的CancellationToken
只会取消委托的starting。如果您希望委托本身支持取消,那么委托本身将不得不遵守 CancellationToken
.
我不确定,但我猜你混淆了“请求取消”与“终止或中止 thread/task”。 这是两个完全不同的东西。根据有关 Canellation in Managerd Threads 的描述,所提供的功能使您能够发送信号之类的东西,表明正在进行的操作应停止。
作为程序员,您如何以及是否对该信号做出反应取决于您。
在您的示例中,您已经开始了一项新任务
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting task...");
var t = new System.Net.Sockets.TcpClient();
var buffer = new byte[t.ReceiveBufferSize];
t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337));
Console.WriteLine("Recieving...");
t.Client.Receive(buffer);
Console.WriteLine("Finished Recieving...");
return true;
}, cts.Token);
不处理取消也不适合这样做。
取消将被使用,例如如果您想跳出多次迭代的循环 - 因此您需要在每次迭代中检查 CancellationToken.IsCancellationRequested
是否已设置为真。
如果是这样,您可以做出相应的反应。
你想要的是中止当前任务背后的线程,在我看来,只有为自己创建 Thread
class 的新实例并相应地处理中止才有可能。