C# 在.NET中使用volatile进行线程之间的单向通信

C# 在.NET中使用volatile进行线程之间的单向通信,c#,.net,multithreading,synchronization,C#,.net,Multithreading,Synchronization,我已经读了很多关于这个主题的帖子,我想我终于明白了volatile关键字在C#中的作用。不过我还是想问一下,以确保我正确理解这些概念。考虑下面的代码: class ThreadWrapper { public bool Enabled { get; set; } private void ThreadMethod() { while (Enabled) { // ... Do work } } } 据我所知,如果另一个线程设置Enabled=false,那么原始线程可

我已经读了很多关于这个主题的帖子,我想我终于明白了
volatile
关键字在C#中的作用。不过我还是想问一下,以确保我正确理解这些概念。考虑下面的代码:

class ThreadWrapper
{
  public bool Enabled { get; set; }

  private void ThreadMethod()
  {
    while (Enabled) { // ... Do work }
  }
}
据我所知,如果另一个线程设置
Enabled=false
,那么原始线程可能不会立即(或者永远)看到此更改。为了确保编译器不会优化对Enabled属性的访问并依赖缓存值,按如下方式更改代码应该可以解决问题

  public bool Enabled { get {return mEnabled;} set {mEnabled=value;} }
  private volatile bool mEnabled;
现在,无论何时读取启用值,都可以保证获得其最新值,对吗?如果是这样的话,我应该能够将它用作一个简单的信号或标志(就像我上面所说的)

作为另一个例子,考虑以下内容:

class C
{
  private volatile int i;
  private volatile bool enabledA;
  private volatile bool enabledB;

  void ThreadA()
  {
    i = 0; // Reset counter
    while (enabledA)
    {
      // .. Do some other repeated work
      if (i > 100)
      {
        // .. Handle threshold case
      }
    }
  }

  void ThreadB()
  {
    while (enabledB)
    {
      // .. Do work
      if (condition) // Some condition occurs that we want to count
      {
        i++;
      }
    }
  }
}
对于这样简单的线程间通信,
volatile
在这里是否令人满意?我知道
I++
不是一个原子操作,但是如果一个线程正在执行所有的递增操作,而另一个线程只是想读取它以查看它是否达到某个阈值,那么我们就可以了,对吗


编辑:我当然是事后才发现的。

我相信你是对的


在其示例中使用了相同的技术。

是的,这应该是安全的,并且是volatile关键字的预期用途之一。但是请注意,您不应该仅仅为了测试条件而循环;如果您只想等待它更改,请使用适当的同步原语以避免浪费CPU时间。还要注意,这种技术之所以有效,是因为只有一个线程在写;如果多个线程试图增加计数器,可能会丢失计数器命中(因为读-修改-写不是原子的)。

我认为这些都是很好的观点。从我所能收集到的信息来看,
volatile
只对上面提到的简单情况有用。我了解到多线程的安全性可能是一项相当棘手的工作。我喜欢在我需要一种方法来标记每个对象的情况下使用volatile,并且我不希望每个对象都有锁。例如,我的一些进行批处理的应用程序有多个线程处理列表中的对象,一个线程在对象完成时写入对象。我只是让工作线程在处理给定对象时翻转一个不稳定的值,而writer线程在遍历列表时只是旋转/休眠等待该值。