首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为实例创建多个syncLock变量

为实例创建多个syncLock变量
EN

Stack Overflow用户
提问于 2011-03-25 01:13:44
回答 3查看 1.9K关注 0票数 4

我有两个内部属性,这两个属性使用延迟加载支持字段,并在多线程应用程序中使用,因此我按照this MSDN article实现了一个双重检查锁方案

现在,首先假设这是一个合适的模式,所有的示例都显示了为一个实例创建一个锁对象。如果我的两个属性彼此独立,那么为每个属性创建一个锁实例不是更有效率吗?

我突然想到,为了避免死锁或竞争条件,可能只有一个。明显的情况不会出现在我的脑海中,但我相信有人可以给我看一个…(显然,我对多线程代码不是很有经验)

代码语言:javascript
复制
private List<SomeObject1> _someProperty1;
private List<SomeObject2> _someProperty2;
private readonly _syncLockSomeProperty1 = new Object();
private readonly _syncLockSomeProperty2 = new Object();

internal List<SomeObject1> SomeProperty1
{
  get
  {
    if (_someProperty1== null)
    {
      lock (_syncLockSomeProperty1)
      {
        if (_someProperty1 == null)
        {
          _someProperty1 = new List<SomeObject1>();
        }
      }
    }
    return _someProperty1;
  }

  set
  {
    _someProperty1 = value;
  }
}

internal List<SomeObject2> SomeProperty2
{
  get
  {
    if (_someProperty2 == null)
    {
      lock (_syncLockSomeProperty2)
      {
        if (_someProperty2 == null)
        {
          _someProperty2 = new List<SomeObject2>();
        }
      }
    }
    return _someProperty2;
  }

  set
  {
    _someProperty2 = value;
  }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-03-25 01:29:49

是的,如果它们是相互独立的,这确实会更有效率,因为访问一个不会阻止对另一个的访问。如果这种独立性被证明是错误的,那么你也有陷入僵局的风险。

问题是,假设_someProperty1 = new List<SomeObject1>();不是赋值给_someProperty1的真正代码(几乎不值得延迟加载,不是吗?),那么问题是:填充SomeProperty1的代码是否可以通过任何代码路径调用填充SomeProperty2的代码,反之亦然,无论代码路径有多奇怪?

即使其中一个可以调用另一个,也不会有死锁,但是如果它们都可以调用对方(或者1个调用2,2个调用3,3个调用1,依此类推),那么肯定会发生死锁。

通常,我会从宽锁开始(一个锁用于所有锁定的任务),然后根据需要优化锁的范围。在你有20个方法需要锁定的情况下,判断安全性可能会更难(而且,你开始只用锁对象填充内存)。

请注意,您的代码还有两个问题:

首先,你没有锁定你的二传手。这可能是好的(你只想让你的锁阻止对加载方法的多次繁重调用,而实际上并不关心setget之间是否有重写),可能这是一场灾难。

其次,根据运行它的CPU,在写入时仔细检查可能会出现读/写重新排序的问题,因此您应该使用易失性字段,或者调用内存屏障。请参阅http://blogs.msdn.com/b/brada/archive/2004/05/12/130935.aspx

编辑:

这也值得考虑是否真的需要它。

考虑到操作本身应该是线程安全的:

  1. 做了很多事情。
  2. 有一个基于对象绑定到局部变量对象的对象。

1和2只会发生在一个线程上,3是原子的。因此,锁定的优点是:

  1. 如果执行上面的步骤 1 和/或 2 有他们自己的线程问题,并且没有被他们自己的锁保护,那么锁定是 100% 必要的。
  2. 如果某事对第 1 步和第 2 步中获得的值采取行动是灾难性的,然后在重复第 1 步和第 2 步的情况下这样做,那么锁定是 100% 必要的。
  3. 锁定将防止多次执行 1 和 2 的浪费。

因此,如果我们可以排除情况1和2作为一个问题(需要一些分析,但这通常是可能的),那么我们只需要防止情况3中的浪费。现在,也许这是一个很大的担忧。然而,如果它很少出现,而且当它出现时也不是那么浪费,那么不加锁的好处将超过加锁的好处。

如果有疑问,锁定可能是更安全的方法,但也有可能只是生活在偶尔浪费的操作更好。

票数 0
EN

Stack Overflow用户

发布于 2011-03-25 01:19:23

如果你的属性是真正独立的,那么对每个属性使用独立的锁也没什么坏处。

票数 3
EN

Stack Overflow用户

发布于 2011-03-25 01:21:07

如果这两个属性(或者更具体地说是它们的初始化器)彼此独立,就像您提供的示例代码中那样,使用两个不同的锁对象是有意义的。但是,当初始化很少发生时,影响将可以忽略不计。

注意,您还应该保护setter的代码。lock语句设置了所谓的内存屏障,这在多CPU和/或多核系统中是必不可少的,以防止竞争条件。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5422919

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档