为了账号安全,请及时绑定邮箱和手机立即绑定

这是使自定义类型线程安全的有效方法吗?以及一般的穿线问题

这是使自定义类型线程安全的有效方法吗?以及一般的穿线问题

C#
收到一只叮咚 2021-03-31 09:23:22
在处理线程时,我有一些一般性问题。我一直在环顾四周,但没有真正看到我的问题的任何答案当您要在一个线程中处理一个类中的多个变量时,是否应该为要锁定在该类中的每个变量都拥有一个“锁定对象”?像这样?static readonly object lockForVarA = new object();private float varA;static readonly object lockForVarB = new object();private float varB;这也是处理线程安全自定义类型的有效方法吗?public class SomeClass{    public SomeClass()    {       //Do some kind of work IE load an assembly    }}public class SomeOtherClass : BaseClassFiringFromRandomThread{    static readonly object someClassLock = new object();    SomeClass someClass;    public override void Init()//this is fired from any available thread, can be fired multiple times and even at the same time    {        lock(someClassLock)        {            if(someClass == null)                someClass = new SomeClass();        }    }}这段代码位于一个类的构造函数中,该类可以随时从任何线程调用
查看完整描述

2 回答

?
宝慕林4294392

TA贡献2021条经验 获得超8个赞

当您要在一个线程中处理一个类中的多个变量时,是否应该为要锁定在该类中的每个变量都拥有一个“锁定对象”?

有两个规则:

  • 要“细粒度”。拥有尽可能多的锁,每个变量一个。每次使用它时,都应在其锁下访问变量。锁定尽可能少的代码以确保可伸缩性。如果忘记锁定变量,则会导致争用情况;如果锁定顺序错误,则会导致死锁,因此请确保其完美无缺。

  • 要“粗粒度”。仅拥有一个锁,然后将所有关键部分放在该锁下。拥有多个锁可以减少争用,但会增加死锁和其他错误的可能性,因此锁应尽可能少,每个锁中要包含尽可能多的代码。当然,这也增加了死锁的风险,因为现在锁中有很多代码可以进行倒置,并且降低了可伸缩性。

毫无疑问,标准建议是完全矛盾的。那是因为锁很糟糕。

我的建议:如果您不跨线程共享变量,则根本不需要任何锁

这也是处理线程安全自定义类型的有效方法吗?

到目前为止,代码看起来还算合理,但是如果您打算延迟加载某些逻辑,则不要编写自己的线程逻辑。只需使用Lazy<T>并使其起作用即可。它是由专家撰写的。

始终使用专家提供的最高级工具。滚动自己的线程原语是灾难的根源。

无论您采取什么措施,都不要采纳另一个答案中的建议,即您必须使用双重检查锁定。有没有什么情况下,你必须使用双重检查锁定。单次检查锁定更安全,更容易且更可能正确。仅在以下情况下使用双重检查锁定:(1)您有大量的经验证据表明争用是可衡量的,影响用户的性能问题的原因,该问题将通过低锁定得到解决,并且(2)您可以解释C#内存模型使双重检查锁定变得安全。

如果您不能执行(1),那么您就没有理由进行双重检查锁定;如果您不能执行(2),则不能放心任何安全性。


查看完整回答
反对 回复 2021-04-10
?
慕的地10843

TA贡献1785条经验 获得超8个赞

您需要使用双重检查的锁定模式。初始化someClass之后,无需获取someClassLock锁,将其锁定在那只会导致不必要的争用。


if (someClass == null)

{

    lock(someClassLock)

    {

        if (someClass == null)

            someClass = new SomeClass();

    }

}

您需要内部if块,因为并发线程可能在第一次空检查之后但在获取锁之前创建了someClass。


当然,您还需要确保以某种本身是线程安全的方式编写SomeClass,但这将安全地确保仅创建someClass的一个实例。


另一种方法是使用Lazy<T>合适的LazyThreadSafetyMode。


查看完整回答
反对 回复 2021-04-10
  • 2 回答
  • 0 关注
  • 199 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信