参考分配线程安全吗?

时间:2011-03-06 09:06:10

标签: c# thread-safety

我正在C#中构建一个多线程缓存,它将包含一个Car对象列表:

public static IList<Car> Cars {get; private set;}

我想知道在没有锁定的情况下更改线程中的引用是否安全?

e.g。

private static void Loop()
{
  while (true)
  {
    Cars = GetFreshListFromServer();
    Thread.Sleep(SomeInterval);
  }
}

基本上,它归结为是否为汽车分配新的参考资料是否是原子的我猜。

如果不是,我显然必须为我的汽车使用私人领域,并锁定获取和设置。

2 个答案:

答案 0 :(得分:59)

是的,参考更新在语言规范中保证是原子的。

  

5.5变量引用的原子性

     

以下数据类型的读写是原子的:bool,char,byte,sbyte,short,ushort,uint,int,float和reference类型。此外,在先前列表中具有基础类型的枚举类型的读取和写入也是原子的。其他类型的读写,包括long,ulong,double和decimal,以及用户定义的类型,不保证是原子的。

然而,在紧密循环中,可能被寄存器缓存咬住。在这种情况下不太可能,除非您的方法调用内联(可能会发生)。我个人会添加lock来简化和预测,但volatile也可以在这里提供帮助。请注意,完整的线程安全不仅仅是原子性。

对于缓存,我会亲自查看Interlocked.CompareExchange - 即尝试进行更新,但如果失败则重做从头开始 strong>(从新值开始)再试一次。

答案 1 :(得分:0)

在@Marc Gravell的回答中,如C#语言规范5.5所述,重要的是要知道术语“用户定义类型”的含义。我没有找到明确的定义w.r.t.这种用法在C#语言规范中。在UML和通常的说法中,Class是Type的实例。但是在C#语言规范的背景下,它的含义还不清楚。

Visual Basic语言参考部分“用户定义的类型”(在https://msdn.microsoft.com/en-us/library/cec05s9z.aspx)说

  

“以前版本的Visual Basic支持用户定义类型(UDT)。当前版本将UDT扩展为结构。”

所以用户定义的Type似乎是一个结构,而不是一个Class。

但是......

根据“C#编程指南”部分“类型”(https://msdn.microsoft.com/en-us/library/ms173104.aspx):

  

“典型的C#程序使用类库中的类型以及   用户定义的类型“

表示Class是用户定义的类型。稍后,它给出了“复杂的用户定义类型:”

的示例
  

MyClass myClass;

表示“MyClass”是用户定义的类型。后来它说:

  

“CTS中的每种类型都被定义为值类型或引用   类型。这包括.NET Framework类中的所有自定义类型   库和也是您自己的用户定义类型。 “

...这意味着开发人员创建的所有类都是“用户定义的类型”。

最后,有一个Stackoverflow项目,其中对该术语的含义进行了无可争议的辩论:How do I determine if a property is a user-defined type in C#?

因此,为了安全起见,我被迫考虑所有类,无论是我创建的类还是.Net Framework中的类,都是用户定义的类型,因此不是线程安全的分配,因为它说在C#语言规范第5.5节中:

  

读取和写入以及用户定义的类型并不保证是原子的。

不幸的是,在C#语言规范等精确规范中使用了口语术语。由于这种模糊性,为了保证线程安全,我可能编写的代码不是最好的,如果事实证明“用户定义的类型”不包括CLR类。

因此,我要求进一步澄清这个stackoverflow答案,因为它的答案的当前基础留下了这种显着的模糊性。就目前而言,问题“参考作业线程安全吗?”的答案似乎是“ NO ”。