不要并发互锁和读取需要一个内存屏障或锁定? [英] Do concurrent interlocked and reads require a memory barrier or locking?

查看:253
本文介绍了不要并发互锁和读取需要一个内存屏障或锁定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个简单的问题,但看完后为什么需要记忆?屏障我对此非常困惑



在下面的例子中,假设不同的线程中一边喊递增和计数器:

 类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 of Counter 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆