【问题标题】:Task::ConfigureAwait - a race condition?Task::ConfigureAwait - 竞争条件?
【发布时间】:2016-03-16 02:02:12
【问题描述】:

想象一下调用者创建任务时的情景:

{
 var tWithCapturedCtx = Task.Run(...);
 var tWithoutCapturedCtx = tWithCapturedCtx.ConfigureAwait(false);

 await tWithoutCapturedCtx;
}

tWithCapturedCtx 是否有可能执行得如此之快,以至于继续将在捕获的上下文中执行?

【问题讨论】:

  • 您的编辑完全改变了问题,并可能使现有/接受的答案无效。请避免此类编辑 - 如果您认为自己没有正确表达您的问题,请随时提出新问题。考虑恢复更改。
  • @user3284063:我回滚了您的编辑,因为它提出了不同的问题。请随时发布新问题。

标签: c# task-parallel-library race-condition


【解决方案1】:

tWithCapturedCtx 是否有可能执行得如此之快,以至于继续将在捕获的上下文中执行?

有点。

如果tWithCapturedCtx 在评估await 时已经完成(这意味着tWithoutCapturedCtx 也已经完成),则根本没有继续。 async 方法只是继续同步执行(在同一上下文中)。

但是,如果在评估 awaittWithCapturedCtx 尚未完成(这意味着 tWithoutCapturedCtx 也尚未完成),则在不捕获上下文的情况下安排继续。

await 检查其可等待对象是否完成与await 安排延续之间还有另一个更小的竞争条件。如果 awaitable 在该窗口内完成,则继续同步运行(同样,在同一上下文中)。

总之,ConfigureAwait(false) 的意思是“我不在乎这个方法的其余部分在什么上下文中运行”;它确实不是的意思是“在线程池上运行此方法的其余部分”。如果您想说“在线程池线程上运行其他代码”,请使用Task.Run

【讨论】:

  • 好的,谢谢。另一个问题:他们为什么不将 continueOnCapturedContext 参数放入 Task::Run 方法的签名中?这样一来,原始任务将根据要完成的上下文来构建。
  • @user3284063:因为这不是任务的责任。只有 调用 代码知道它是否需要在捕获的上下文中恢复。这是“配置等待”,而不是“配置任务”。
  • @StephenCleary 旁注:OP 编辑​​了我认为显着改变了问题的问题 - 请检查一下,看看是否应该回滚编辑(或者您可能想更新答案,我也认为这会有些错误)。
【解决方案2】:

ConfigureAwait 被调用在延续被添加到任务之前。延续被添加到配置为不捕获上下文的对象中,因此它不会在其延续运行时捕获上下文(这实际上就是它存在的目的,如果它没有)。

【讨论】:

  • 抱歉,我可能不太清楚 - 请查看更新后的问题
猜你喜欢
  • 2022-01-23
  • 2018-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多