如果你有一个锁码块内共享变量的多任务,它意味着所有这些变化立刻反馈给其他线程可见,在其它处理器上可能运行的,一旦他们对同一个对象进入一个锁声明-或者是有没有这样的保证?
很多的例子在那里显示了一个单一的 “设置”或公共变量的“获取”和进入的内存屏障的细节,但会发生什么,如果一个更复杂的语句集合在里面? 甚至可能函数调用,做其他事情?
事情是这样的:
lock(sharedObject)
{
x = 10;
y = 20;
z = a + 10;
}
如果这个代码在另一个线程,这是另一处理器上执行的可能运行,它作任何保证对变化的“可见度”?
lock (sharedObject)
{
if (y == 10)
{
// Do something.
}
}
如果答案是否定的-也许是和当这些变化可能成为可见的解释?
锁定块包括在开始时的存储器围栏和在终点(开始和所述块的端部)。 这确保了对存储器的任何变化都将其他核(在其它核心上运行例如其他线程)可见。 在你的榜样,改变X,Y,Z在你的第一个锁块将是任何其他线程可见。 “可见”是指缓存到一个寄存器中的任何值将被刷新到存储器中,并且在CPU中的缓存中的任何存储器将被刷新到物理存储器。 ECMA 334点的细节,锁块是由Monitor.Enter和Monitor.Exit包围的块。 此外,ECMA 335细节Monitor.Enter“应隐式执行挥发性读操作......”和Monitor.Exit“隐式执行挥发性的写操作,这是否意味着修改不会对其他核心/线程,直到可见锁块的一端(Monitor.Exit后),但如果所有的这些变量的访问被锁保护,就不可能有同时访问说,在不同的核心/线程变量反正。
这实际上意味着,由lock语句把守任何变量不需要被声明为volatile,以便有其修改其他线程可见。
由于示例代码只包含依赖于一个单一的共享原子操作的操作(读取和单个值的y写),你可以得到相同的结果有:
try
{
x = 10;
y = 20;
Thread.VolatileWrite(ref z, a + 10);
}
和
if(y == 10)
{
// ...
}
第一块保证写入到x是写入到y和写入到y之前可见是写入到z之前是可见的。 这也保证,如果写入x或y在CPU中的高速缓存中高速缓存的高速缓存将调用VolatileWrite后立即刷新到物理内存(从而对任何其他线程可见)。
如果内if(y == 10)
阻止你做的东西x
和y
,你应该恢复使用lock
的关键字。
此外,以下将是相同的:
try
{
x = 10;
y = 20;
Thread.MemoryBarrier();
z = a + 10;
}
原谅我,如果我误解你的问题(很可能); 但我认为你在迷茫混合的同步和可见性的概念操作。
互斥(“互斥”)的整点是要确保两个代码块将不能同时运行。 所以,在你的榜样,第一块:
lock(sharedObject)
{
x = 10;
y = 20;
z = a + 10;
}
...和第二块:
lock (sharedObject)
{
if (y == 10)
{
// Do something.
}
}
将永远不会在同一时间执行 。 这就是lock
关键字保证你。
因此, 任何时候你的代码已经进入了第二块,变量x
, y
,和z
应该是在与第一的完整执行一致的状态。 (这是假设你到处访问这些变量,你lock
的sharedObject
在你的这些片段具有相同的方式。)
这意味着,所述的第一个块内的中间变化“能见度”是从第二的角度无关,因为绝不会有时,例如,在改变为值的时间x
已经发生但不y
或z
。
文章来源: Does a lock statement around multiple statements ensure that all the changes are visible to other threads (provided they enter the same mutex)?