我需要这个字段是不稳定的吗?

时间:2012-04-25 00:20:20

标签: c# .net multithreading volatile

我有一个旋转的线程,直到另一个线程更改的int是某个值。

int cur = this.m_cur;
while (cur > this.Max)
{
    // spin until cur is <= max
    cur = this.m_cur; 
}

是否需要将this.m_cur声明为volatile以使其正常工作?由于编译器优化,它是否可能永远旋转?

3 个答案:

答案 0 :(得分:12)

是的,这是一项艰难的要求。允许即时编译器将m_cur的值存储在处理器寄存器中,而无需从内存中刷新它。实际上x86抖动确实存在,x64抖动没有(至少是我最后一次看到它)。

volatile 关键字是抑制此优化所必需的。

易失性意味着Itanium内核,一个内存模式较弱的处理器完全不同。不幸的是,它成为了MSDN库和C#语言规范的原因。它在ARM核心上意味着什么还有待观察。

答案 1 :(得分:4)

下面的博客有一些关于c#内存模型的精彩细节。简而言之,使用volatile关键字似乎更安全。

http://igoro.com/archive/volatile-keyword-in-c-memory-model-explained/

来自下面的博客

class Test
{
    private bool _loop = true;

    public static void Main()
    {
        Test test1 = new Test();

        // Set _loop to false on another thread
        new Thread(() => { test1._loop = false;}).Start();

        // Poll the _loop field until it is set to false
        while (test1._loop == true) ;

        // The loop above will never terminate!
    }
}
  

有两种方法可以让while循环终止:使用a   锁定以保护对_loop字段的所有访问(读取和写入)   将_loop字段标记为volatile有两个原因可以读取a   非易失性字段可能会观察到陈旧的值:编译器优化   和处理器优化。

答案 2 :(得分:0)

这取决于m_cur的修改方式。如果它使用正常的赋值语句,例如m_cur--;,那么它确实需要是volatile。但是,如果使用其中一个Interlocked操作对其进行修改,则不会因为Interlocked的方法会自动插入内存屏障以确保所有线程都获得备忘录。

通常,使用Interlocked来修改跨线程共享的原子值是更好的选择。它不仅为您处理内存障碍,而且往往比其他同步选项更快。

就是说,像其他人一样说投票循环非常浪费。最好暂停需要等待的线程,让任何正在修改m_cur的人负责在时机成熟时将其唤醒。根据您的具体需求,Monitor.Wait() and Monitor.Pulse()AutoResetEvent可能都非常适合此任务。