如果我在一个线程上创建一个变量,然后使用ManualResetEvent
的WaitOne()
方法阻塞,直到另一个线程为同一个变量分配一个值并向EventWaitHandel
发送信号。当我在第一个线程上读取变量时,我保证总是得到另一个线程分配的值吗?
(我担心我无法从CPU缓存中获得值,因为据我所知,我还没有使用任何内存屏障)。
例如:
var str = "multi-threading is hard!";
var mre = new ManualResetEvent(false);
Task.Factory.StartNew(() =>
{
str = Console.ReadLine();
mre.Set();
));
mre.WaitOne();
Console.WriteLine(str);
发布于 2014-02-21 09:06:37
这些指令不会被重新排序,这意味着在生成线程上,字段分配总是在句柄发出信号之前发生,而在消费线程上,字段总是在句柄发出信号后被读取。
如果这两对指令中的任何一条可以重新排序(例如,如果第二个线程可以在句柄发出信号之前读取字段),那么您将看不到正确的值。
WaitOne()
引入了一个隐式内存屏障,为您提供了所需的获取释放语义。
Brian和Hans列出了.NET框架中引入隐式内存屏障的几个类的列表:记忆屏障发生器
更多信息:获取和发布语义 / 获取和释放围栏
发布于 2014-02-21 09:03:11
您的变量是一个捕获的变量,即编译器将这个局部变量转换为编译器生成的类的字段,因为您在lambda表达式中使用它。Afaik,这些编译器生成的字段没有标记为volatile
,因此可以缓存它们。
编辑:实际上,字段是不稳定的。
您可以通过编写自己的类来防止缓存,这样编译器就不必创建缓存。然而,这当然妨碍了代码的简洁性。
https://stackoverflow.com/questions/21929644
复制相似问题