C# · 12月 30, 2021

C#中的Volatile和Thread.MemoryBarrier

为了实现多线程应用程序的无锁代码,我使用了volatile变量,
理论上讲:volatile关键字只是用来确保所有线程都看到一个volatile变量的最新值;所以如果线程A更新变量值,并且线程B在发生更新之后读取该变量,它将看到最近从线程A写入的最新值.
当我在一个Cuts 4.0中看到一个Nut shell的书
这是不正确的因为

applying volatile doesn’t prevent a write followed by a read from being swapped.

可以通过将Thread.MemoryBarrier()放在volatile变量的每个get之前解决这个问题,如:

private volatile bool _foo = false;private void A(){ //… Thread.MemoryBarrier(); if (_foo) { //do somthing }}private void B(){ //… _foo = true; //…}

如果这样解决问题;考虑到我们有一个while循环,在其条件之一依赖于该值;在Thread.MemoryBarrier()之前,while循环是一个正确的方法来解决问题?例:

private void A(){ Thread.MemoryBarrier(); while (_someOtherConditions && _foo) { // do somthing. }}

为了更准确,我希望_foo变量在任何线程在任何时候提供最新值;所以如果在调用变量之前插入Thread.MemoryBarrier()来修复问题,那么我可以使用Foo属性而不是_foo,并在该属性的get中执行Thread.MemoryBarrier().Like:

Foo{ get { Thread.MemoryBarrier(); return _foo; } set { _foo = value; }}解决方法 “C#在一个坚果”是正确的,但它的声明是愚蠢的.为什么?

> A’write’后跟’read’,withot’volatile’,如果它在单个线程中影响逻辑,就保证以程序顺序发生
>在多线程程序中’read’之前的’write’在你的例子中是毫无意义的.

我们来澄清一下拿你的原始代码:

private void A() { //… if (_foo) { //do something } }

如果线程调度程序已经检查了_foo变量,但是在执行某些注释之前它会被暂停呢?那么在那个时候你的其他线程可以改变_foo的值,这意味着你所有的挥发物和Thread.MemoryBarriers都没有计数!如果_foo的值为false,绝对必须避免do_something,那么您别无选择,只能使用一个锁.

然而,如果在突然_foo变为false时执行某些操作是可行的,那么这意味着volatile关键字足以满足您的需求.

要明确:所有正在告诉你使用记忆障碍的回复者都是错误的或者是提供过度的杀伤力.