字符串属性本身是线程安全的吗?

Tom*_*Tom 30 c# multithreading

C#中的字符串是不可变的和线程安全的.但是当你有一个公共吸气剂属性时呢?像这样:

public String SampleProperty{
    get;
    private set;
}
Run Code Online (Sandbox Code Playgroud)

如果我们有两个线程,第一个是调用'get'而第二个是在"相同"时调用'set',会发生什么?

恕我直言,该集必须锁定为线程安全,如下所示:

private string sampleField;
private object threadSafer = new object();

public String SampleProperty{
    get{ return this.sampleField; }
    private set{
        lock(threadSafer){
            sampleField = value;
        }
    }
 }
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 41

大多数答案都使用"原子"这个词,好像原子变化都是需要的.他们通常不是.

这已在评论中提及,但通常不在答案中 - 这是我提供此答案的唯一原因.(关于以较粗粒度锁定,允许附加等内容的观点也是完全有效的.)

通常,您希望读取线程查看变量/属性的最新值.原子性无法保证一点.作为一个简单的例子,这是一个阻止线程的方法:

class BackgroundTaskDemo
{
    private bool stopping = false;

    static void Main()
    {
        BackgroundTaskDemo demo = new BackgroundTaskDemo();
        new Thread(demo.DoWork).Start();
        Thread.Sleep(5000);
        demo.stopping = true;
    }

    static void DoWork()
    {
         while (!stopping)
         {
               // Do something here
         }
    }
}
Run Code Online (Sandbox Code Playgroud)

DoWork可能永远循环,尽管写入布尔变量是原子的 - 没有什么可以阻止JIT缓存stoppingin 的值DoWork.要解决此问题,您需要锁定,生成变量volatile或使用显式内存屏障.这也适用于字符串属性.


Mar*_*ell 17

引用类型字段的get/set(ldfld/stfld)是(IIRC)保证是原子的,所以这里不应该有任何损坏的风险.因此,从这个角度来看它应该是线程安全的,但我个人将数据锁定在更高的级别 - 即

lock(someExternalLock) {
    record.Foo = "Bar";
}
Run Code Online (Sandbox Code Playgroud)

或者可能:

lock(record.SyncLock) {
    record.Foo = "Bar";
}
Run Code Online (Sandbox Code Playgroud)

这允许您对原子操作对同一对象进行多次读取/更新,以便其他线程无法获得无效的对象状态