简体   繁体   English

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

[英]Do I need this field to be volatile?

I have a thread that spins until an int changed by another thread is a certain value. 我有一个旋转的线程,直到另一个线程更改的int是某个值。

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

Does this.m_cur need to be declared volatile for this to work? this.m_cur是否需要声明为volatile才能生效? Is it possible that this will spin forever due to compiler optimization? 由于编译器优化,它是否有可能永远旋转?

Yes, that's a hard requirement. 是的,这是一个很难的要求。 The just-in-time compiler is allowed to store the value of m_cur in a processor register without refreshing it from memory. 允许即时编译器将m_cur的值存储在处理器寄存器中,而无需从内存中刷新它。 The x86 jitter in fact does, the x64 jitter doesn't (at least the last time I looked at it). 实际上x86抖动确实存在,x64抖动没有(至少我最后一次看它)。

The volatile keyword is required to suppress this optimization. 需要使用volatile关键字来抑制此优化。

Volatile means something entirely different on Itanium cores, a processor with a weak memory model. 易失性意味着Itanium内核,一个内存模式较弱的处理器完全不同。 Unfortunately that's what made it into the MSDN library and C# Language Specification. 不幸的是,它成为了MSDN库和C#语言规范的原因。 What it is going to to mean on an ARM core remains to be seen. 它在ARM核心上意味着什么还有待观察。

The blog below has some fascinating detail on the memory model in c#. 下面的博客有一些关于c#内存模型的精彩细节。 In short, it seems safer to use the volatile keyword. 简而言之,使用volatile关键字似乎更安全。

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

From the blog below 来自下面的博客

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!
    }
}

There are two possible ways to get the while loop to terminate: Use a lock to protect all accesses (reads and writes) to the _loop field Mark the _loop field as volatile There are two reasons why a read of a non-volatile field may observe a stale value: compiler optimizations and processor optimizations. 有两种方法可以使while循环终止:使用锁来保护对_loop字段的所有访问(读取和写入)将_loop字段标记为volatile有两个原因可以解释为什么读取非易失性字段陈旧的值:编译器优化和处理器优化。

It depends on how m_cur is being modified. 这取决于m_cur的修改方式。 If it's using a normal assignment statement such as m_cur--; 如果它使用正常的赋值语句,如m_cur--; , then it does need to be volatile. ,那确实需要是不稳定的。 However, if it's being modified using one of the Interlocked operations, then it doesn't because Interlocked's methods automatically insert a memory barrier to ensure that all threads get the memo. 但是,如果使用其中一个Interlocked操作对其进行修改,则不会因为Interlocked的方法自动插入内存屏障以确保所有线程都获得备忘录。

In general, using Interlocked to modify atomic valued that are shared across threads is the preferable option. 通常,使用Interlocked来修改跨线程共享的原子值是更好的选择。 Not only does it take care of the memory barrier for you, but it also tends to be a bit faster than other synchronization options. 它不仅为您处理内存屏障,而且往往比其他同步选项快一点。

That said, like others have said polling loops are enormously wasteful. 也就是说,像其他人一样说投票循环非常浪费。 It would be better to pause the thread that needs to wait, and let whoever is modifying m_cur take charge of waking it up when the time comes. 最好暂停需要等待的线程,让任何正在修改m_cur的人负责在时机成熟时将其唤醒。 Both Monitor.Wait() and Monitor.Pulse() and AutoResetEvent might be well-suited to the task, depending on your specific needs. Monitor.Wait()和Monitor.Pulse()以及AutoResetEvent都可能非常适合该任务,具体取决于您的具体需求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM