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