我有以下情况:
var tmp1 = new MyObject() { A = i, B = 2 };
// ** write barrier here??
this.Obj = tmp1;
另一个线程可以做类似这样的事情:
var tmp = this.Obj;
// ** read barrier here??
use(tmp.A);
像 'Obj' 这样的对象只需要编写一次,然后被多个线程(多次)读取。
我知道 Obj 在两个线程中均不为 null。我也不关心 'this.Obj' 的同步。我关心的是,一旦我读取了引用 tmp = Obj
,那么内容(如 A
和 B
)也是有效的。
我的问题是:我是否需要在上面标记的位置设置内存屏障(例如 Thread.MemoryBarrier();
)来确保这一点,还是这总是隐含的 OK?
人们似乎不喜欢这个问题。
我的问题源于以下情况。我已经阅读了有关内存栅栏的资料,它们保证:(引用)
执行当前线程的处理器不能以使内存访问在调用 MemoryBarrier 之前执行,而在调用 MemoryBarrier 之后执行的方式重新排序指令。
如果你看一下代码,CPU / 编译器可能能够重新编写代码:
var tmp1 = new MyObject();
tmp1.A = i;
tmp1.B = 2;
this.Obj = tmp1;
更糟糕的是:
var tmp1 = new MyObject();
this.Obj = tmp1;
tmp1.A = i;
tmp1.B = 2;
如果另一个线程取走了最后的案例,它可以从内存中读取
this.Obj
,而A
和B
仍然具有默认值。请注意,这不仅仅是编译器能够重新排序的问题;这也涉及到CPU允许重新排序的问题。
换句话说:(感谢@MattBurland)是否保证对象初始化器在将tmp1分配给
this.Obj
之前运行?还是我需要使用内存栅栏来手动确保这一点?
this
不是关键字。我更关心的是您应该在何时使用这些概念(我已经阅读了大量的互联网信息,这是我理解应该如何使用它们,但我仍然觉得很困惑)。至于C ++的备注 - 我对概念感兴趣,这应该适用于任何语言...据我所知,这些概念是'read','write'和'full' fences,其中Thread.MemoryBarrier
是一个完整的fence。 - atlastethis.Obj
是可变的,并且读取线程可能会更改A
和/或B
。但是你说你不关心同步问题。 - Matt BurlandMyObject
的内容吗?那么你应该从对象内部寻找解决方法,例如通过将其设置为只读或不可变。 - Panagiotis Kanavostmp1
赋值给this.Obj
之前,对象初始化程序是否保证会运行。是这样吗?我希望是这样,但实际上我并不确定。 - Matt Burlandthis.Obj
是一个字段,则可以使用Volatile.Write(this.Obj, tmp1);
如果不是,则可以拥有一个static volatile int _barrier;
,然后执行:_barrier = 0; this.Obj = tmp1;
- xanatos