5

我有一个始终被阻止的任务,并且我有一个 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)所以我不得不调用它在另一个线程上。

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

4

3 回答 3

2

[更新]

我将代码更改为以下解决了问题:

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);
于 2014-03-29T20:40:28.730 回答
2

您可以使用Registeron 方法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“如何:注册取消请求的回调”

于 2015-07-08T07:59:06.120 回答
-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但第一个对于您的场景应该足够了。

于 2014-03-29T19:08:33.673 回答