C#锁定免费编码健全检查

her*_*son 1 c# multithreading volatile

更新:现在使用基于以下评论的只读集合

我相信下面的代码应该是线程安全的"锁定免费"代码,但是要确保我没有遗漏某些东西......

public class ViewModel : INotifyPropertyChanged
{
   //INotifyPropertyChanged and other boring stuff goes here...

   private volatile List<string> _data;
   public IEnumerable<string> Data
   {
      get { return _data; }
   }

   //this function is called on a timer and runs on a background thread
   private void RefreshData()
   {
      List<string> newData = ACallToAService();
      _data = newData.AsReadOnly();
      OnPropertyChanged("Data"); // yes, this dispatches the to UI thread
   }
}
Run Code Online (Sandbox Code Playgroud)

具体来说,我知道我可以使用一个lock(_lock)甚至是一个Interlocked.Exchange()但我不相信在这种情况下需要它.volatile关键字应该足够(以确保不缓存该值),不是吗?有人可以确认一下,或者让我知道我对线程的理解不清楚:)

Eri*_*ert 7

我不知道这是否"安全"; 它取决于你所说的"安全".例如,如果将"安全"定义为"保证从所有线程中观察到所有易失写入的一致排序",则不保证您的程序在所有硬件上都是"安全的".

这里最好的做法是使用锁,除非你有充分的理由不这样做.写这个有风险的代码你有什么理由?

更新:我的观点是,低锁或无锁代码风险极高,世界上只有少数人真正了解它.让我举一个例子,来自Joe Duffy:

// deeply broken, do not use!
class Singleton {
    private static object slock = new object();
    private static Singleton instance;
    private static bool initialized;
    private Singleton() {}
    public Instance {
        get {
            if (!initialized) {
                lock (slock) {
                    if (!initialized) {
                        instance = new Singleton();
                        initialized = true;
                    }
                }
            }
            return instance;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这段代码坏了; 正确实现C#编译器为您编写一个为该实例返回null的程序是完全合法的.你能看到怎么样?如果没有,那么你没有做低锁或无锁编程的业务; 你弄错的.

我自己也弄不清楚这些东西; 它打破了我的大脑.这就是为什么我试图永远不做低锁编程,这种编程与专家分析的标准实践完全不同.


Mar*_*ell 5

这取决于意图是什么.列表的get/set是原子的(即使没有volatile)和非缓存的(volatile),但是调用者可以改变列表,这保证是线程安全的.

还有一种竞争条件可能会丢失数据:

 obj.Data.Add(value);
Run Code Online (Sandbox Code Playgroud)

这里的价值很容易被抛弃.

我会使用一个不可变(只读)集合.