CancellationToken和CancellationTokenSource-如何使用它?

Mik*_*ike 7 c# task-parallel-library c#-4.0

我有一个名为Load的UI按钮.它产生一个线程,反过来产生一个任务.任务等待,如果过期,任务将被取消."加载"按钮未禁用,用户可以多次单击它.每次单击时,都应取消上一个任务.

我对如何在这里使用CancellationTokenSource和CancellationToken感到困惑.下面是代码.您能否建议如何使用它以及以下用法是否有任何问题?请不要异步,因为我们还没有.

CancellationTokenSource _source = new CancellationTokenSource();
        public void OnLoad()
        {
            //Does this cancel the previously spawned task?
            _source.Cancel();
            _source.Dispose();
            _source = new CancellationTokenSource();
            var activeToken = _source.Token;
            //Do I need to do the above all the time or is there an efficient way?

            Task.Factory.StartNew(() =>
                {
                    var child = Task.Factory.StartNew(() =>
                        {
                            Thread.Sleep(TimeSpan.FromSeconds(20));
                            activeToken.ThrowIfCancellationRequested();
                        }, activeToken);

                    if (!child.Wait(TimeSpan.FromSeconds(5)))
                    {
                        _source.Cancel();
                    }
                });
        }
Run Code Online (Sandbox Code Playgroud)

注意我需要取消任何以前生成的任务,并且每个生成的任务都应该超时.

Jam*_*urt 9

这样做:

    private CancellationTokenSource _cancelTasks;

    // this starts your process
    private void DoStuff()
    {
        _cancelTasks = new CancellationTokenSource();

        var task = new Task(() => { /* your actions here */ }, _cancelTasks.Token);
        task.Start();

        if (!task.Wait(5000)) _cancelTasks.Cancel();
    }
Run Code Online (Sandbox Code Playgroud)

  • 不要忘记处理 `CancellationTokenSource`。 (4认同)

Pan*_*vos 5

首先,如果您使用的是Visual Studio 2012+,则可以添加Microsoft.Bcl.Async软件包,以便为async.NET 4.0项目添加支持和其他高级功能.

如果您使用的是Visual Studio 2010,则可以使用WithTimeoutParallelExtensionsExtras库附带的扩展方法.该方法使用TaskCompletionSource和一个调用SetCancelled它的计时器包装原始Task .

代码在这里,但实际的方法很简单:

    /// <summary>Creates a new Task that mirrors the supplied task but that 
    /// will be canceled after the specified timeout.</summary>
    /// <typeparam name="TResult">Specifies the type of data contained in the 
    /// task.</typeparam>
    /// <param name="task">The task.</param>
    /// <param name="timeout">The timeout.</param>
    /// <returns>The new Task that may time out.</returns>
    public static Task<TResult> WithTimeout<TResult>(this Task<TResult> task, 
                                                          TimeSpan timeout)
    {
        var result = new TaskCompletionSource<TResult>(task.AsyncState);
        var timer = new Timer(state => 
                        ((TaskCompletionSource<TResult>)state).TrySetCanceled(),
                        result, timeout, TimeSpan.FromMilliseconds(-1));
        task.ContinueWith(t =>
        {
            timer.Dispose();
            result.TrySetFromTask(t);
        }, TaskContinuationOptions.ExecuteSynchronously);
        return result.Task;
    }
Run Code Online (Sandbox Code Playgroud)

您可以在创建任务后立即使用它:

var myTask=Task.Factory.StartNew(()=>{...})
           .WithTimeout(TimeSpan.FromSeconds(20));
Run Code Online (Sandbox Code Playgroud)

通常,您可以通过创建调用其SetResult,SetCancelled方法的TaskCompletionSource来响应您设置的事件或条件来创建所需的行为.