Dod*_*bit 4 c# synchronization locking thread-safety
如果您在一个锁代码块内有多个共享变量的分配,是否一定意味着所有这些更改对其他线程立即可见,一旦它们在同一对象上输入锁语句就可能在其他处理器上运行 - 或者没有这样的保证?
那里的许多示例显示了一个公共变量的单个“设置”或“获取”,并详细介绍了内存屏障,但是如果内部有一组更复杂的语句会发生什么?甚至有可能做其他事情的函数调用?
像这样的东西:
lock(sharedObject)
{
x = 10;
y = 20;
z = a + 10;
}
Run Code Online (Sandbox Code Playgroud)
如果此代码在另一个线程上运行,而该线程可能在另一个处理器上执行,它是否对更改的“可见性”做出任何保证?
lock (sharedObject)
{
if (y == 10)
{
// Do something.
}
}
Run Code Online (Sandbox Code Playgroud)
如果答案是否定的- 也许并解释何时这些变化可能变得可见?
一个锁块在开始和结束处(块的开始和结束)包括一个内存栅栏。这确保了对内存的任何更改对其他内核(例如,在其他内核上运行的其他线程)都是可见的。在您的示例中,任何其他线程都可以看到第一个锁块中对 x、y、z 的更改。“可见”意味着缓存到寄存器中的任何值都将刷新到内存中,而缓存在 CPU 缓存中的任何内存都将刷新到物理内存中。ECMA 334 详细说明锁块是由 Monitor.Enter 和 Monitor.Exit 包围的块。此外,ECMA 335 详细说明 Monitor.Enter“应隐式执行易失性读取操作...”和 Monitor.Exit“隐式执行易失性写操作。这确实意味着修改不会”
这实际上意味着由 lock 语句保护的任何变量不需要声明为 volatile 以便其他线程可以看到它们的修改。
由于示例代码仅包含一个依赖于单个共享原子操作(读取和写入 y 的单个值)的操作,您可以获得相同的结果:
try
{
x = 10;
y = 20;
Thread.VolatileWrite(ref z, a + 10);
}
Run Code Online (Sandbox Code Playgroud)
和
if(y == 10)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
第一个块保证对 x 的写入在写入 y 之前可见,对 y 的写入在写入 z 之前可见。它还保证,如果对 x 或 y 的写入缓存在 CPU 缓存中,则该缓存将在调用 VolatileWrite 后立即刷新到物理内存(从而对任何其他线程可见)。
如果在if(y == 10)
块中使用x
and做某事y
,则应该返回使用lock
关键字。
此外,以下内容是相同的:
try
{
x = 10;
y = 20;
Thread.MemoryBarrier();
z = a + 10;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1239 次 |
最近记录: |