【问题标题】:Is readonly variable thread safe? [duplicate]只读变量线程安全吗? [复制]
【发布时间】:2012-11-13 02:52:54
【问题描述】:

可能重复:
Is a readonly field in C# thread safe?

一个相当简单的程序

private readonly string _data1;
private readonly int _data2;
private readonly MyAnotherClass _data3;

public MyClass(string data1, int data2, MyAnotherClass data3)
{
    _data1 = data1;
    _data2 = data2;
    _data3 = data3;
}

_data1, _data2 and _data3 线程安全吗?

【问题讨论】:

标签: c# multithreading


【解决方案1】:

只读变量保证在被访问之前被初始化。初始值是在对象的构造过程中分配的,在对象被完全分配之前。

变量初始化器被转换为赋值语句,这些赋值语句在基类实例构造函数调用之前执行。这种排序确保所有实例字段在执行任何有权访问该实例的语句之前由其变量初始化器初始化

参考:C# 规范,10.11.3 构造函数执行(重点是我的)

对只读字段的赋值只能作为字段声明的一部分或在同一类的构造函数中发生

参考:C# 规范,1.6.5 字段

因此,该值将在任何线程可用之前设置,并且不会更改,因此它是线程安全的。

【讨论】:

  • 我在问一个构造函数。一般来说,构造函数线程中的变量是否安全?
  • 是的,它们是线程安全的。在完全构造给定的对象实例之前,编译器不会返回该对象,并且任何线程都可以访问该对象。添加了对 C# 规范的引用以阐明这一点。
  • 好吧,静态构造函数是绝对线程安全的,因为它在 App Domain 中只被调用一次。实例构造函数也是这样吗?
  • @Alexandre:是的。尝试想象在程序中引用可用之前可以访问类的字段或属性的代码。换句话说,给定MyClass my = new MyClass();,在实际从new MyClass() 分配实例之前,您如何访问my 的字段或属性?
【解决方案2】:

是的,因为一旦构建了类,任何软件都无法更改它们。

编辑

虽然数据字段是线程安全的,但 _data3 的内容不是线程安全的。不同的线程可以“同时”修改 _data3。

【讨论】:

  • 一个构造函数可以同时调用多个线程吗?
  • 是的,但是你会构造一个不同的对象;所以没有线程安全问题。
  • +1。尤其是_data3 的线程安全。
  • > 请解释一下。他们可以在构造函数中修改它吗?
  • @Alexandre,任何人都可以在任何地方修改 _data3.SomeField。
【解决方案3】:

Joh Skeets 在 Is a readonly field in C# thread safe? 的回答给出了大部分答案 - 对于不可变类型(如 int/string),它是线程安全的。

如果自定义类型不是不可变的,引用本身将是线程安全的,但readonly 不保证对象的任何内容。所以_data3对象的所有属性都需要有自定义的线程安全保护。

【讨论】:

    【解决方案4】:

    只要您以后不更改它们,是的。

    编辑:

    class Class1
    {
    
        readonly string bigbuddy;
    
        public Class1()
        {
    
            bigbuddy = "1";
    
            Thread thread1 = new Thread(SomeThread);
            thread1.Start(this);
    
            Thread.Sleep(1000);
    
            bigbuddy = "2";
    
            Thread thread2 = new Thread(SomeThread);
            thread2.Start(this);
    
        }
    
        public void SomeThread(object state) {
    
            Class1 class1 = (Class1)state;
    
            Debug.WriteLine(class1.bigbuddy);
    
        }
    
    
    }
    

    用途:

     Class1 asd = new Class1();
    

    输出:

    1
    The thread '<No Name>' (0xe0c) has exited with code 0 (0x0).
    2
    The thread '<No Name>' (0x129c) has exited with code 0 (0x0).
    

    【讨论】:

    • 向我展示如何在构造后更改只读变量的值...(我猜可能通过反射可以实现,但这违背了只读的意义)。
    • -1 因为 readonly 以后无法更改。
    • @BernaMariano:没必要粗鲁。
    • A readonly 可以稍后使用反射进行更改。
    • 请看我添加的例子,仍然是线程安全的?
    猜你喜欢
    • 2016-07-13
    • 1970-01-01
    • 2011-01-24
    • 1970-01-01
    • 2014-12-12
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    相关资源
    最近更新 更多