【问题标题】:Are memory-barriers required when joining on a thread?加入线程时是否需要内存屏障?
【发布时间】:2012-09-08 19:42:32
【问题描述】:

如果线程 A 生成另一个线程 B 的唯一目的是写入变量 V,然后等待它终止,是否需要内存屏障来确保线程 A 上对 V 的后续读取是新鲜的?我不确定终止/加入操作中是否有任何隐含的障碍使它们变得多余。

这是一个例子:

public static T ExecuteWithCustomStackSize<T>
    (Func<T> func, int stackSize)
{
    T result = default(T);

    var thread = new Thread(
        () => 
                {
                    result = func();
                    Thread.MemoryBarrier(); // Required?
                }
        , stackSize);

    thread.Start();
    thread.Join();

    Thread.MemoryBarrier(); // Required?
    return result;
}

是否需要上述 sn-p 中的一个/两个(或多个)障碍?

【问题讨论】:

标签: c# .net multithreading thread-safety memory-barriers


【解决方案1】:

不,同步机制会生成隐式内存栅栏。线程加入后,线程修改的所有数据都可见。

【讨论】:

  • 感谢您的回答。有什么文件可以支持吗?
  • @Ani:在这个来源:albahari.com/threading/part4.aspx(现在每个人都知道),他们提到几乎所有同步机制都会生成栅栏。他们没有明确提到Join,但因为它使调用线程处于与Monitor.Wait 相同的状态,例如,这是一个强烈的暗示,它也应该生成一个栅栏。此外,还提到了等待Task。虽然加入线程有点不同,但我希望它能够提供相同的内存排序保证。
  • 我确实读过那篇文章,但不确定这是结论性的,因为就像你说的那样,它没有明确提到 Join
  • @Ani:嗯,我一直在网上搜索,每个人似乎都在这样的讨论中忽略了Thread.Join。我什至尝试查看 MS 发布的一些旧的 .NET 库代码,但 Join 进入本机代码。我想我能给你的唯一保证是:“它暂停调用线程,所以它可能在内部使用一个事件”,“它应该生成一个栅栏,否则会违反 join 的一般语义" 和 "在 Java 中是生成一个栅栏"。 :))
  • 非常感谢您对此进行调查!
【解决方案2】:

从文档看来它们不是必需的 -

仅在内存排序较弱的多处理器系统(例如,采用多个 Intel Itanium 处理器的系统)上才需要MemoryBarrier。

对于大多数用途,C# lock 语句、Visual Basic SyncLock 语句或 Monitor 类提供了更简单的数据同步方法。

由于您使用 join 进行阻塞,因此更没有必要。

【讨论】:

    【解决方案3】:

    您不需要第一个内存屏障。 您只需要在访问已在单独线程中修改的数据之前调用它们。 由于您没有在“线程”内这样做,因此您不需要调用。

    如果您打算保留加入通话,则可以摆脱第二个。 如果你保持第二个电话,你可以摆脱加入。

    【讨论】:

      猜你喜欢
      • 2016-03-01
      • 2017-08-23
      • 2011-10-12
      • 2014-01-20
      • 2012-05-27
      • 2017-01-05
      • 2015-04-01
      • 2014-05-29
      • 1970-01-01
      相关资源
      最近更新 更多