Tom*_*Tom 30 c# multithreading
C#中的字符串是不可变的和线程安全的.但是当你有一个公共吸气剂属性时呢?像这样:
public String SampleProperty{
    get;
    private set;
}
如果我们有两个线程,第一个是调用'get'而第二个是在"相同"时调用'set',会发生什么?
恕我直言,该集必须锁定为线程安全,如下所示:
private string sampleField;
private object threadSafer = new object();
public String SampleProperty{
    get{ return this.sampleField; }
    private set{
        lock(threadSafer){
            sampleField = value;
        }
    }
 }
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
         }
    }
}
DoWork可能永远循环,尽管写入布尔变量是原子的 - 没有什么可以阻止JIT缓存stoppingin 的值DoWork.要解决此问题,您需要锁定,生成变量volatile或使用显式内存屏障.这也适用于字符串属性.
Mar*_*ell 17
引用类型字段的get/set(ldfld/stfld)是(IIRC)保证是原子的,所以这里不应该有任何损坏的风险.因此,从这个角度来看它应该是线程安全的,但我个人将数据锁定在更高的级别 - 即
lock(someExternalLock) {
    record.Foo = "Bar";
}
或者可能:
lock(record.SyncLock) {
    record.Foo = "Bar";
}
这允许您对原子操作对同一对象进行多次读取/更新,以便其他线程无法获得无效的对象状态