Cancellation token in Task constructor: why?

徘徊边缘 提交于 2019-11-26 02:05:42

问题


Certain System.Threading.Tasks.Task constructors take a CancellationToken as a parameter:

CancellationTokenSource source = new CancellationTokenSource();
Task t = new Task (/* method */, source.Token);

What baffles me about this is that there is no way from inside the method body to actually get at the token passed in (e.g., nothing like Task.CurrentTask.CancellationToken). The token has to be provided through some other mechanism, such as the state object or captured in a lambda.

So what purpose does providing the cancellation token in the constructor serve?


回答1:


Passing this token into the Task constructor associates it with this task.

Quoting Stephen Toub's answer from MSDN:

This has two primary benefits:

  1. If the token has cancellation requested prior to the Task starting to execute, the Task won't execute. Rather than transitioning to Running, it'll immediately transition to Canceled. This avoids the costs of running the task if it would just be canceled while running anyway.
  2. If the body of the task is also monitoring the cancellation token and throws an OperationCanceledException containing that token (which is what ThrowIfCancellationRequested does), then when the task sees that OperationCanceledException, it checks whether the OperationCanceledException's token matches the Task's token. If it does, that exception is viewed as an acknowledgement of cooperative cancellation and the Task transitions to the Canceled state (rather than the Faulted state).



回答2:


The constructor uses the token for cancellation handling internally. If your code would like access to the token you are responsible for passing it to yourself. I would highly recommend reading the Parallel Programming with Microsoft .NET book at CodePlex.

Example usage of CTS from the book:

CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken token = cts.Token;

Task myTask = Task.Factory.StartNew(() =>
{
    for (...)
    {
        token.ThrowIfCancellationRequested();

        // Body of for loop.
    }
}, token);

// ... elsewhere ...
cts.Cancel();



回答3:


Cancellation is not a simple a case as many might think. Some of the subtleties are explained in this blog post on msdn:

For example:

In certain situations in Parallel Extensions and in other systems, it is necessary to wake up a blocked method for reasons that aren't due to explicit cancellation by a user. For example, if one thread is blocked on blockingCollection.Take() due to the collection being empty and another thread subsequently calls blockingCollection.CompleteAdding(), then the first call should wake up and throw an InvalidOperationException to represent an incorrect usage.

http://blogs.msdn.com/b/pfxteam/archive/2009/06/22/9791840.aspx



来源:https://stackoverflow.com/questions/3712939/cancellation-token-in-task-constructor-why

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!