- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
考虑一个 Winforms 应用程序,我们有一个生成一些结果的按钮。如果用户第二次按下按钮,它应该取消第一次生成结果的请求并开始一个新的请求。
我们正在使用以下模式,但我们不确定是否需要某些代码来防止竞争条件(请参阅注释掉的行)。
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
。我们想知道以下事件序列是否可能:
CancellationToken
尚未取消)。任务调度程序将工作发布到 Windows 消息队列(以使其在主线程上运行)。CancellationTokenSource
被取消。所以,我认为问题归结为:
当工作发布到主线程时(通过使用 TaskScheduler.FromCurrentSynchronizationContext()
),TPL 会在执行任务操作之前检查主线程上的 CancellationToken
,或者它会在它恰好所在的任何线程上检查取消 token ,然后将工作发布到 SynchronizationContext
?
最佳答案
假设我没看错问题,你担心的是以下事件序列:
T0
被调度到线程池上,continuation C0
被调度为T0
的continuation,待在同步上下文的任务调度器上运行T0
完成,这导致 C0
被发布到消息队列。队列现在包含两项,点击处理程序和 C0
的执行。T0
和 C0
的取消。然后它以与步骤 1
相同的方式在线程池和 C1
上安排 T1
作为延续。C0
”消息仍在队列中,因此现在得到处理。它是否执行您打算取消的延续?答案是否定的。 TryExecuteTask不会执行已发出取消信号的任务。该文档暗示了它,但在 TaskStatus 上明确说明了页面,它指定
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
将处于 Canceled
状态。
当然,这就是假设当前 SynchronizationContext
不允许任务并发运行(如您所知,Windows 窗体不允许 - 我只是注意到这不是同步上下文的要求)
此外,值得注意的是,关于是否在请求取消或执行任务的上下文中检查取消 token 的最后一个问题的确切答案,答案确实是两者 .除了在 TryExecuteTask
中进行最终检查外,一旦请求取消,框架就会调用 TryDequeue
,这是任务调度程序可以支持的可选操作。同步上下文调度程序不支持它。但如果它以某种方式做到了,区别可能在于“执行 C0
”消息将完全从线程的消息队列中删除,它甚至不会尝试执行任务。
关于c# - 与 CancellationToken 的竞争条件,其中 CancellationTokenSource 仅在主线程上取消,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15660942/
有人可以向我澄清主线 DHT 规范中的声明吗? Upon inserting the first node into its routing table and when starting up th
我正在尝试使用 USB 小工具驱动程序使嵌入式设备作为 MTP 设备工作。 我知道 Android 从大容量存储设备切换到 MTP 设备已经有一段时间了,并且找到了 source code for M
我是一名优秀的程序员,十分优秀!