不要并发互锁和读取需要一个内存屏障或锁定? [英] Do concurrent interlocked and reads require a memory barrier or locking?
问题描述
这是一个简单的问题,但看完后为什么需要记忆?屏障我对此非常困惑
在下面的例子中,假设不同的线程中一边喊递增和计数器:
类Foo {
INT _counter = 0;
公众诠释柜台
{
{返回_counter; }
}
公共无效增量()
{
Interlocked.Increment(REF _counter);
}
}
很抱歉,如果我误解的Why我需要一个内存屏障?但似乎像它暗示上述类可能不可以提供的新鲜感保证的阅读_counter的价值时。难道一个线程的重复访问计数器财产获得永远停留在计数器(因为它是在寄存器缓存)的旧值?
是一个内存屏障或锁前收益_counter;
必要
是一个内存屏障或返回_counter前锁;有必要吗?
块引用>
是的,绝对。请看下面的代码。
而(foo.Counter == 0)
{
//待办事项东西
}
的问题是,如果在循环内的内容是足够简单那么。C#编译器,JIT编译器或硬件将优化以这种方式代码
INT寄存器= foo._counter;
,而(寄存器== 0)
{
//做些什么
}
甚至这一点。
如果(foo._counter == 0)
{
START:
//做些什么
转到START;
}
请注意,我用
_counter
而不是计数
为暗示该财产可能会被内联的方式。然后,更重要的是,JIT编译器可能会升降机_counter
的循环之外的读取,以便它是只读一次。
记忆障碍,不提供的新鲜感保证的本身。他们所做的就是防止某些软件或硬件的优化,重新排序读取和写入内存。在新鲜感保障的是更多的副作用真的。
所以要包东西你的
计数
属性应该是这样的。公众诠释柜台
{
{返回互锁。 CompareExchange(参考_counter,0,0); }
}
This is a simple problem, but after reading Why do I need a memory barrier? I'm very confused about it.
In the example below, assume different threads are repeatedly calling Increment and Counter:
class Foo{ int _counter=0; public int Counter { get { return _counter; } } public void Increment() { Interlocked.Increment(ref _counter); } }
Sorry if I'm misinterpreting Why do I need a memory barrier? but it seems like it's suggesting the class above might not be providing a freshness guarantee when reading the value of _counter. Could a thread that's repeatedly accessing the Counter property get forever stuck on an old value of Counter (because it is cached in the register)?
Is a memory barrier or a lock before
return _counter;
necessary?解决方案Is a memory barrier or a lock before return _counter; necessary?
Yes, absolutely. Consider the following code.
while (foo.Counter == 0) { // Do something }
The problem is that if the contents inside the loop are simple enough then the C# compiler, JIT compiler, or hardware will optimize the code in this manner.
int register = foo._counter; while (register == 0) { // Do something }
Or even this.
if (foo._counter == 0) { START: // Do something goto START; }
Notice that I use
_counter
instead ofCounter
as a way of implying that the property will probably be inlined. Then, more importantly, the JIT compiler may "lift" the read of_counter
outside of the loop so that it is only read once.Memory barriers do not provide a freshness guarantee per se. What they do is prevent certain software or hardware optimizations that reorder reads and writes to memory. The freshness guarantee is more of a side effect really.
So to wrap things up your
Counter
property should look like this.public int Counter { get { return Interlocked.CompareExchange(ref _counter, 0, 0); } }
这篇关于不要并发互锁和读取需要一个内存屏障或锁定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!