.net Interlocked.MemoryBarrierProcessWide()在内部是如何工作的?

3okqufwl  于 2023-11-20  发布在  .NET
关注(0)|答案(1)|浏览(130)

根据这篇文章:https://www.albahari.com/threading/part4.aspx我们知道volatile并不能阻止写操作和读操作的交换,这可能会引起一些脑筋急转弯:

class IfYouThinkYouUnderstandVolatile
{
  volatile int x, y;
 
  void Test1()        // Executed on one thread
  {
    x = 1;            // Volatile write (release-fence)
    int a = y;        // Volatile read (acquire-fence)
    ...
  }
 
  void Test2()        // Executed on another thread
  {
    y = 1;            // Volatile write (release-fence)
    int b = x;        // Volatile read (acquire-fence)
    ...
  }
}

字符串
有可能a和b都以0结束(尽管在x和y上都使用了volatile):
文章来源:https://onurgumus.github.io/2021/02/07/Demystifying-the-volatile-keyword.html
我们可以把这个例子修改为

方案一

class IfYouThinkYouUnderstandVolatile
{
  volatile int x, y;
 
  void Test1()        // Executed on one thread
  {
    x = 1;            
    Interlocked.MemoryBarrier();
    int a = y;        
    ...
  }
 
  void Test2()        // Executed on another thread
  {
    y = 1; 
    Interlocked.MemoryBarrier();          
    int b = x;
    ...
  }
}

方案二

class IfYouThinkYouUnderstandVolatile
{
  volatile int x, y;
 
  void Test1()        // Executed on one thread
  {
    x = 1;            
    Interlocked.MemoryBarrierProcessWide();
    int a = y;        
    ...
  }
 
  void Test2()        // Executed on another thread
  {
    y = 1; 
    int b = x;
    ...
  }
}


我对解决方案二有疑问。我可以得到这样的观点,可能存在第三种方法。这样的代码使用相同的变量可能隐藏在不同的库中,我们可能不知道它。这就是为什么作者使用Interlocked.MemoryBarrierProcessWide();
但是由于Interlocked.MemoryBarrierProcessWide();只在一个地方使用,编译器如何知道它需要在Test2方法的指令中插入另一个内存屏障,甚至是访问这些字段的另一个方法?

4xrmg8kj

4xrmg8kj1#

该实现简单地调用Windows API函数FlushProcessWriteBuffers()
该函数生成一个处理器间中断(IPI)到当前进程关联的所有处理器。
参见here for more details
所以为了回答你的问题“既然Interlocked.MemoryBarrierProcessWide();只在一个地方使用,编译器如何知道它需要在Test 2方法的指令中插入另一个内存屏障”:
编译器不需要这样做,因为对FlushProcessWriteBuffers()的调用将影响运行任何代码的所有处理器。

相关问题