【问题标题】:Multiplexing C# 5.0's async over a thread pool -- thread safe?在线程池上多路复用 C# 5.0 的异步——线程安全吗?
【发布时间】:2012-11-01 14:47:53
【问题描述】:

这可能看起来有点疯狂,但如果我可以合理地确定它不会导致奇怪的行为,我正在考虑将它作为一个更大的库的一部分。

方法:

使用分配到线程池的SynchronizationContext 运行异步用户代码。用户代码如下所示:

async void DoSomething()
{
    int someState = 2;
    await DoSomethingAsync();
    someState = 4;
    await DoSomethingElseAsync();
    // someState guaranteed to be 4?
}

我不确定对someState 的访问是否是线程安全的。虽然代码将在一个“线程”中运行,这样操作实际上是完全有序的,但它仍然可以在底层的多个线程中拆分。如果我的理解是正确的,那么在 x86 上排序应该是安全的,而且由于变量不是共享的,我不需要担心编译器优化等等。

但更重要的是,我担心这是否会在 ECMA 或 CLR 内存模型下保证线程安全。

我相当肯定我需要在执行排队的工作之前插入一个内存屏障,但我对我的推理并不完全有信心(或者这种方法可能由于完全不同的原因而行不通)。

【问题讨论】:

  • 它是一个局部变量。它怎么可能不是线程安全的? IOW 是什么让您认为它可以在另一个线程中更改? (除非您在未显示的某处传递对它的引用,即 ref 或作为捕获的变量)。
  • 据我了解,await 将以下代码转换为一个延续,当底层Task 完成时,该延续将在当前SynchronizationContext 上执行。如果这是分派到线程池,那么延续可以在不同的线程上运行。它不会以任何方式同时运行,但我不确定如果继续在不同的物理线程上执行,是否可以保证对someState 的更改可见。
  • 这是一个很好的问题,很多人甚至都不知道要问。

标签: c# thread-safety threadpool async-await


【解决方案1】:

async / await FAQ 的 cmets 部分对此进行了回答:

TPL 在任务排队时和任务执行的开始/结束时包括适当的障碍,以便适当地使值可见。

因此不需要明确的障碍。

【讨论】:

    猜你喜欢
    • 2020-02-04
    • 2018-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-15
    • 2011-04-06
    • 2017-03-12
    • 2010-12-22
    相关资源
    最近更新 更多