mar*_*osb 3 c# multithreading thread-safety shared-memory memory-barriers
这是一个简单的问题,但在阅读之后我为什么需要内存屏障?我很困惑.
在下面的示例中,假设不同的线程重复调用Increment和Counter:
class Foo{
int _counter=0;
public int Counter
{
get { return _counter; }
}
public void Increment()
{
Interlocked.Increment(ref _counter);
}
}
Run Code Online (Sandbox Code Playgroud)
对不起,如果我误解了为什么我需要内存屏障?但似乎这表明上述课程在阅读_counter的价值时可能无法提供新鲜度保证.重复访问Counter属性的线程是否会永远停留在旧的Counter值(因为它缓存在寄存器中)?
在return _counter;必要之前是内存屏障还是锁?
返回_counter之前是内存屏障还是锁定; 必要?
是的,一点没错.请考虑以下代码.
while (foo.Counter == 0)
{
// Do something
}
Run Code Online (Sandbox Code Playgroud)
问题是如果循环内的内容足够简单,那么C#编译器,JIT编译器或硬件将以这种方式优化代码.
int register = foo._counter;
while (register == 0)
{
// Do something
}
Run Code Online (Sandbox Code Playgroud)
甚至这个.
if (foo._counter == 0)
{
START:
// Do something
goto START;
}
Run Code Online (Sandbox Code Playgroud)
请注意,我使用的方式_counter不是Counter暗示该属性可能会被内联.然后,更重要的是,JIT编译器可以"提升" _counter循环外部的读取,以便只读取一次.
记忆障碍本身并不提供新鲜度保证.他们所做的是阻止某些软件或硬件优化,这些优化会重新排序对内存的读写操作.该新鲜感保证更多的是一种副作用真的.
所以把你的Counter财产包起来应该是这样的.
public int Counter
{
get { return Interlocked.CompareExchange(ref _counter, 0, 0); }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
986 次 |
| 最近记录: |