C#:CancellationToken 不会取消阻塞方法

问题描述 投票:0回答:2

.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 http://stackoverflow.com/questions/9208921/async-on-main-method-of-console-app
    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...

为什么任务没有取消,没有抛出异常?

c# task-parallel-library
2个回答
6
投票

正如我在博客上所说,“你一直在那里使用那个

CancellationToken
。我不认为这意味着你认为的意思。”

特别是,传递给

CancellationToken
StartNew
只会取消委托的starting。如果您希望委托本身支持取消,那么委托本身必须遵守
CancellationToken


3
投票

我不确定,但我猜您将“请求取消”与“终止或中止线程/任务”混淆了。 这是两个完全不同的事情。根据有关“托管线程中的取消”的描述,所提供的功能使您能够发送类似信号的内容,指示正在进行的操作应停止。 作为程序员,你如何以及是否对该信号做出反应取决于你。

在您的示例中,您已经开始了一项新任务

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

是否已设置为 true 。 如果是这样,您可以做出相应的反应。

您想要的是中止当前任务背后的线程,在我看来,这只能通过为自己创建 

Thread

类的新实例并相应地处理中止来实现。

    

© www.soinside.com 2019 - 2024. All rights reserved.