thr*_*thr 5 .net c# mono multithreading thread-safety
简化了问题,以更清楚地表达我实际要求的内容
我有两个线程,叫他们A和B.它们共享一个类型的对象,Foo该对象具有一个被调用的字段Name,并存储Foo[]在索引处的类型数组中0.线程将始终0按照系统保证的顺序访问索引,因此线程B之前没有线程获取的竞争条件A.
顺序是这样的.
 // Thread A
 array[0].Name = "Jason";
 // Thread B
 string theName = array[0].Name
Run Code Online (Sandbox Code Playgroud)
正如我所说,这个顺序已经得到保证,线程B无法在线程A之前读取该值
我想要确保的是两件事:
B始终在.Name字段中获取最新值      标记Name为易失性不是一种选择,因为真实对象要复杂得多,甚至还有自定义结构甚至不能附加volatile属性.
现在,满足1很容易(总是得到最新的对象),你可以做一个.VolatileRead:
 // Thread A
 Foo obj = (Foo)Thread.VolatileRead(ref array[0]);
 obj.Name = "Jason";
 // Thread B
 Foo obj = (Foo)Thread.VolatileRead(ref array[0]);
 string theName = obj.Name
Run Code Online (Sandbox Code Playgroud)
或者您可以插入内存屏障:
 // Thread A
 array[0].Name = "Jason";
 Thread.MemoryBarrier();
 // Thread B
 Thread.MemoryBarrier();
 string theName = array[0].Name
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:这还足以满足条件2吗?我总是从我读出的对象的字段中获得最新值?如果索引处的对象0没有改变,但是Name已经改变了.执行a VolatileRead或MemoryBarrieron索引0会确保索引对象中的所有字段0也获取其最新值吗?
这些解决方案lock都volatile不能解决您的问题。因为:
volatile确保一个线程更改的变量对于操作相同数据的其他线程立即可见(即它们不会被缓存),并且不会重新排序对该变量的操作。并不是你真正需要的。lock确保写/读不会同时发生,但不保证它们的顺序。这取决于哪个线程首先获得锁,这是不确定的。因此,如果您的流程是:
Thread A read Name
Thread A modify Name
Thread B read Name
Run Code Online (Sandbox Code Playgroud)
正是按照这个顺序,您需要通过事件来强制执行它(AutoresetEvent例如):
//Thread A
foo[0].Name = "John"; // write value
event.Set(); // signal B that write is completed
//Thread B
event.WaitOne(); // wait for signal
string name = foo[0].Name; // read value
Run Code Online (Sandbox Code Playgroud)
这保证了线程 B 在 A 修改 Name 变量之前不会读取该变量。
编辑:好的,所以您确定遵守上述流程。既然你说你不能声明 fields volatile,我建议使用Thread.MemoryBarrier()来引入强制排序的栅栏:
//Thread A
foo[0].Name = "John"; // write value
Thread.MemoryBarrier();
//Thread B
Thread.MemoryBarrier();
string name = foo[0].Name; // read value
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请查看此文档:http://www.albahari.com/threading/part4.aspx