C#:CancellationToken没有取消阻止方法

时间:2015-11-22 13:46:11

标签: c# task-parallel-library

.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...

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

2 个答案:

答案 0 :(得分:6)

正如我在博客上所说:"You keep using that CancellationToken there. I do not think it means what you think it means."

特别是,传递给CancellationToken的{​​{1}}只会取消委托的开始。如果您希望代理本身支持取消,那么代理本身必须遵守StartNew

答案 1 :(得分:3)

我不确定,但我猜你是在混淆“请求取消”而“终止或中止线程/任务”。 这是两个完全不同的东西。根据关于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);

不处理取消也不适合这样做。 例如,可以使用Canellation。如果你想要通过多次迭代打破循环 - 因此你会在每次迭代中检查CancellationToken.IsCancellationRequested是否已设置为true。 如果是这样,你可以做出相应的反应。

你想要的是中止当前任务背后的线程,我认为这只能为你自己创建Thread类的新实例并相应地处理中止。