考虑一个WinForms应用程序,在这里我们有一个生成一些成果的按钮。如果用户按下按钮的第二时间,就应该取消,以产生结果,并开始一个新的第一请求。
Consider a Winforms application, where we have a button that generates some results. If the user presses the button a second time, it should cancel the first request to generate results and start a new one.
我们正在使用下面的模式,但我们不能确定,如果一些代码是必要的,以防止竞争条件(见注释行)。
We're using the below pattern, but we are unsure if some of the code is necessary to prevent a race condition (see the commented out lines).
private CancellationTokenSource m_cts; private void generateResultsButton_Click(object sender, EventArgs e) { // Cancel the current generation of results if necessary if (m_cts != null) m_cts.Cancel(); m_cts = new CancellationTokenSource(); CancellationToken ct = m_cts.Token; // **Edit** Clearing out the label m_label.Text = String.Empty; // **Edit** Task<int> task = Task.Run(() => { // Code here to generate results. return 0; }, ct); task.ContinueWith(t => { // Is this code necessary to prevent a race condition? // if (ct.IsCancellationRequested) // return; int result = t.Result; m_label.Text = result.ToString(); }, ct, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.FromCurrentSynchronizationContext()); }注意:
- 我们永远只能取消 CancellationTokenSource 在主线程上。
- 我们使用相同的的CancellationToken 在延续,我们在原来做任务。
- We only ever cancel the CancellationTokenSource on the main thread.
- We use the same CancellationToken in the continuation as we do in the original task.
我们想知道是否还是不活动的下列顺序是可能的:
We're wondering whether or not the following sequence of events is possible:
所以,我认为这个问题可以归结为:
So, I think the question boils down to:
当工作被发送到主线程(通过使用 TaskScheduler.FromCurrentSynchronizationContext())不TPL的检查的CancellationToken 在主线程上执行前任务的行动,或者它检查任何线程恰好是在取消标记,然后发布工作到的SynchronizationContext ?
When work is posted to the main thread (by using TaskScheduler.FromCurrentSynchronizationContext()) does the TPL check the CancellationToken on the main thread before executing the task's action, or does it check the cancellation token on whatever thread it happens to be on, and then post the work to the SynchronizationContext?
推荐答案假设我正确读取的问题,你担心的事件顺序如下:
Assuming I read the question correctly, you are worried about the following sequence of events:
答案是否定的。 TryExecuteTask 将不会执行任务,被通知注销。它是由该文档暗示,但在 TaskStatus明确规定了页面,指定
The answer is no. TryExecuteTask will not execute a task which has been signaled for cancellation. It's implied by that documentation, but spelled out explicitly on the TaskStatus page, which specifies
的取消的 - 任务通过抛出OperationCanceledException承认其取消自己的CancellationToken而令牌信号状态中,或任务的的CancellationToken面前的任务开始执行
Canceled -- The task acknowledged cancellation by throwing an OperationCanceledException with its own CancellationToken while the token was in signaled state, or the task's CancellationToken was already signaled before the task started executing.
因此,在这一天结束 T0 将在 RanToCompletion 状态和 C0 将在取消状态。
So at the end of the day T0 will be in the RanToCompletion state and C0 will be in the Canceled state.
这是一切,当然,假设当前的SynchronizationContext 不允许任务同时运行(如你所知,Windows窗体一个没有 - 我只是指出的是,这不是一个同步上下文的要求)
This is all, of course, assuming that the current SynchronizationContext does not allow tasks to be run concurrently (as you are aware, the Windows Forms one does not -- I'm just noting that this is not a requirement of synchronization contexts)
另外,值得一提的是,确切的回答你关于取消标记是否是当请求撤销或者上下文检查最后一个问题任务执行时,答案是真的两个的。除了最后的检查在 TryExecuteTask ,尽快取消请求该框架将调用 TryDequeue ,可选的操作该任务调度程序能够支持。该同步上下文调度程序不支持它。但是,如果它在某种程度上确实,区别可能是,执行 C0 的消息会被完全撕开了线程的消息队列中,它甚至不会尝试执行任务。
Also, it's worth noting that the exact answer to your final question about whether the cancellation token is checked in the context of when cancellation is requested or when the task is executed, the answer is really both. In addition to the final check in TryExecuteTask, as soon as cancellation is requested the framework will call TryDequeue, an optional operation that task schedulers can support. The synchronization context scheduler does not support it. But if it somehow did, the difference might be that the 'execute C0' message would be ripped out of the thread's message queue entirely and it wouldn't even try to execute the task.
更多推荐
用的CancellationToken竞争状态,其中CancellationTokenSource只取消了主线程
发布评论