根据这篇文章: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方法的指令中插入另一个内存屏障,甚至是访问这些字段的另一个方法?
1条答案
按热度按时间4xrmg8kj1#
该实现简单地调用Windows API函数
FlushProcessWriteBuffers()
:该函数生成一个处理器间中断(IPI)到当前进程关联的所有处理器。
参见here for more details
所以为了回答你的问题“既然Interlocked.MemoryBarrierProcessWide();只在一个地方使用,编译器如何知道它需要在Test 2方法的指令中插入另一个内存屏障”:
编译器不需要这样做,因为对
FlushProcessWriteBuffers()
的调用将影响运行任何代码的所有处理器。