繁体   English   中英

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

[英]Is a string property itself threadsafe?

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;
        }
    }
 }

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

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

通常你想要一个阅读线程来查看变量/属性的最新值。 原子性无法保证一点 作为一个简单的例子,这是一个阻止线程的方法:

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缓存在DoWorkstopping的值。 要解决此问题,您需要锁定,使变量变为volatile或使用显式内存屏障。 这也适用于字符串属性。

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

lock(someExternalLock) {
    record.Foo = "Bar";
}

或者可能:

lock(record.SyncLock) {
    record.Foo = "Bar";
}

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

设置字符串是一个原子操作,即你将获得新字符串或旧字符串,你永远不会得到垃圾。

如果你正在做一些工作,例如

obj.SampleProperty = "Dear " + firstName + " " + lastName;

然后字符串连接全部发生在调用set之前,因此sampleField将始终是新字符串或旧字符串。

但是,如果您的字符串连接代码是自引用的,例如

obj.SampleProperty += obj.SampleProperty + "a";

或者你在另一个线程上的位置

obj.SampleProperty = "Initial String Value";

然后你需要锁。

考虑一下你正在使用int。 如果您要分配int,并且从int获得的任何值都是有效的,那么您不需要锁定它。

但是,如果int保持由两个或多个线程处理的小部件数量的计数,为了使计数准确,您需要锁定int。 字符串的情况也是如此。

我有一种感觉,我没有很好地解释这一点,希望它有所帮助。

谢谢

BW

这是线程安全的,无需锁定。 字符串是引用类型,因此仅修改对字符串的引用。 参考类型保证是原子的(32位系统上的Int32和64位上的Int64)。

你的第二个代码示例肯定是不对的,因为当锁在访问变量的所有地方(包括get set)使用时,锁只会产生预期的效果,所以get也需要一个锁。

但是,当获取并将引用类型字段设置为这样的属性时,添加锁定语句不会添加任何值。 指针的赋值在.NET环境中保证是原子的,如果多个线程正在更改属性,那么无论如何你都有一个固有的竞争条件(线程可能看到不同的值;这可能是也可能不是问题)所以几乎没有指向锁定。

所以对于它的作用,第一段代码很好。 但是,您是否真的想在多线程应用程序中构建固有的竞争条件是另一回事。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM