7

我一直在阅读类似问题的答案,但我仍然有点困惑......亚伯有一个很好的答案,但这是我不确定的部分:

...声明一个变量 volatile 使其在每次访问时都是 volatile 的。不可能以任何其他方式强制这种行为,因此 volatile 不能用 Interlocked 代替。这在其他库、接口或硬件可以访问您的变量并随时更新它或需要最新版本的情况下是必需的。

是否Interlocked保证原子操作对所有线程的可见性,还是我仍然必须volatile在值上使用关键字以保证更改的可见性?

这是我的例子:

volatile int value = 100000; // <-- do I need the volitile keyword
// ....

public void AnotherThreadMethod()
{
 while(Interlocked.Decrement(ref value)>0)
 {
  // do something
 }
}


public void AThreadMethod()
{
 while(value > 0)
 {
  // do something
 }
}

更新:
我是一项糟糕的运动,我改变了原来的例子,所以又是这样:

public class CountDownLatch
{
    private volatile int m_remain; // <--- do I need the volatile keyword here?
    private EventWaitHandle m_event;

    public CountDownLatch(int count)
    {
        Reset(count);
    }

    public void Reset(int count)
    {
        if (count < 0)
            throw new ArgumentOutOfRangeException();
        m_remain = count;
        m_event = new ManualResetEvent(false);
        if (m_remain == 0)
        {
            m_event.Set();
        }
    }

    public void Signal()
    {
        // The last thread to signal also sets the event.
        if (Interlocked.Decrement(ref m_remain) == 0)
            m_event.Set();
    }

    public void Wait()
    {
        m_event.WaitOne();
    }
}
4

2 回答 2

6

它们不需要*波动性,因为您从不检查联锁变量的值。相反,您总是检查联锁操作返回的值。混合互锁操作和普通的赋值/比较总是会导致错误的代码。

我不确定 Reset() 函数的意图是什么,但那段代码在线程间原语中没有位置:你分配给 m_remain,你直接检查 m_remain 的值,这很糟糕。我强烈建议你把它拿出来:不仅实现不正确,而且我高度怀疑是否需要“重置”计数器中年的语义。保持简单:ctor(将代码从 Reset 移到其中) Signal 和 Wait 是唯一需要的三个运算符,它们现在是正确的。

编辑代码后更新。

忽略您不应该将两者混合的事实,如果您最终将它们混合,那么是的,仍然需要 volatile。Volatile 主要是关于 IL 代码和生成的 JIT 代码,以确保始终从实际内存位置读取值并且不会发生优化,例如代码重新排序。一段不相关的代码使用互锁操作更新值这一事实对读取该值的其他部分没有影响。如果没有oavolatile属性,编译器/JIT 仍可能生成忽略其他地方发生的写入的代码,与写入是互锁的还是直接赋值无关。

顺便说一句,有混合普通读取和互锁操作的有效模式,但它们通常涉及 Interlocked.CompareExchange 和这样的 go:读取当前状态,基于当前状态进行一些计算,尝试将状态替换为互锁比较交换:如果成功则正常,如果不成功则丢弃计算结果并返回步骤 1。

于 2010-03-19T06:02:02.503 回答
2

我认为 System.Threading.Thread.VolatileRead(ref myVariable) 可能是您正在寻找的。与 Interlocked.Increment 结合使用,它可用于保证更改是原子的,并且您读取的值是最新的。

于 2010-03-23T17:22:25.410 回答