如何使用取消令牌取消C#中的阻止任务?

时间:2014-03-29 19:04:06

标签: c# task-parallel-library cancellation-token

我有一个始终被阻止的任务,我有一个CancellationToken传入其中,用于取消任务。但是,永远不会执行Continuation任务,该任务设置为在Task的取消时执行。代码是:

    _tokenSrc = new CancellationTokenSource();
    var cnlToken = _tokenSrc.Token;

    Task.Run(() => 
          // _stream.StartStream() blocks forever  
          _stream.StartStream(), cnlToken)
        .ContinueWith(ant =>
        {
            _logger.Warn("Stream task cancellation requested, stopping the stream");
            _stream.StopStream();
            _stream = null;
            _logger.Warn("Stream stopped and task cancelled");
        }, TaskContinuationOptions.OnlyOnCanceled);

稍后在代码中的其他地方...

_tokenSrc.Cancel();

我必须为_stream.StartStream()使用任务的原因是这个调用永远阻塞(我无法控制的api,注意_stream指的是从web服务传输数据的第三方Api)所以我不得不在另一个线程上调用它。

取消任务的最佳方法是什么?

3 个答案:

答案 0 :(得分:1)

[UPDATE]

我将代码更改为下面修复了问题:

Task.Run(() =>
{
    var innerTask = Task.Run(() => _stream.StartStream(), cToken);
    innerTask.Wait(cToken);
}, cToken)
.ContinueWith(ant =>
{
    _logger.Warn("Stream task cancellation requested, stopping the stream");
    _stream.StopStream();
    _stream = null;
    _logger.Warn("Stream stopped and task cancelled");
}, TaskContinuationOptions.OnlyOnCanceled);

答案 1 :(得分:0)

您可以使用Register上的CancellationToken方法注册将在请求取消时调用的委托。在委托中,您调用解锁阻止操作的方法。

类似的东西:

_tokenSrc = new CancellationTokenSource();
var cnlToken = _tokenSrc.Token;

var task = Task.Factory.StartNew(() =>
{
    using(var tokenReg = cnlToken.Register(() => 
        {
            _logger.Warn("Stream task cancellation requested, stopping the stream");
            _stream.StopStream();
            _stream = null;
            _logger.Warn("Stream stopped and task cancelled");
        }))
    {
        _stream.StartStream(), cnlToken)
    }
}, cnlToken);

MSDN "How to: Register Callbacks for Cancellation Requests"

答案 2 :(得分:-1)

此处清楚地描述了如何使用取消令牌:http://msdn.microsoft.com/en-us/library/dd997396(v=vs.110).aspx,其中包含建议的模式。

我会在页面出现故障时报告示例:

using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
    static void Main()
    {

        var tokenSource2 = new CancellationTokenSource();
        CancellationToken ct = tokenSource2.Token;

        var task = Task.Factory.StartNew(() =>
        {

            // Were we already canceled?
            ct.ThrowIfCancellationRequested();

            bool moreToDo = true;
            while (moreToDo)
            {
                // Poll on this property if you have to do 
                // other cleanup before throwing. 
                if (ct.IsCancellationRequested)
                {
                    // Clean up here, then...
                    ct.ThrowIfCancellationRequested();
                }

            }
        }, tokenSource2.Token); // Pass same token to StartNew.

        tokenSource2.Cancel();

        // Just continue on this thread, or Wait/WaitAll with try-catch: 
        try
        {
            task.Wait();
        }
        catch (AggregateException e)
        {
            foreach (var v in e.InnerExceptions)
                Console.WriteLine(e.Message + " " + v.Message);
        }

        Console.ReadKey();
    }
}

这里有一个更深入的例子:http://msdn.microsoft.com/en-us/library/dd537607(v=vs.110).aspx但第一个应该足够你的场景。