已更新:现在使用基于以下评论的只读集合
我相信下面的代码应该是线程安全的“无锁”代码,但我想确保我没有遗漏任何东西......
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
}
}
具体来说,我知道我可以使用 lock(_lock)
甚至 Interlocked.Exchange()
但我认为没有必要在这种情况下。 volatile 关键字应该足够了(以确保该值未被缓存),不是吗?有人可以确认这一点,或者让我知道我对线程不了解的地方:)
我不知道这是否“安全”;这完全取决于您所说的“安全”是什么意思。例如,如果您将“安全”定义为“保证从所有线程观察到所有 volatile 写入的一致顺序”,那么您的程序不保证在所有硬件上都是“安全”的。
此处的最佳做法是使用锁,除非您有充分的理由不这样做。 您编写这段有风险的代码的极好的理由是什么?
更新:我的观点是低锁或无锁代码极度危险并且世界上只有少数人真正理解它。让我给你举个例子,来自 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;
}
}
}
此代码已损坏; C# 编译器的正确实现为您编写一个为实例返回 null 的程序是完全合法的。 你能看出如何吗?如果不是,那么您就没有资格进行低锁或无锁编程;你会弄错。
我自己搞不懂这些东西;它打破了我的大脑。这就是为什么我尽量不进行以任何方式偏离专家分析的标准实践的低锁编程。
我是一名优秀的程序员,十分优秀!