1

我在访问共享变量的多线程环境中有一些代码。显然我需要lock这些访问,但我的问题是我是否通过在短时间内锁定变量以获取值、解锁、用我检索到的内容做一些事情、然后重新锁定来修改来节省创建额外的开销我刚刚解锁的数据结构。

显然,对于可以在锁之外完成的非常昂贵的操作,您将受益于不锁定该段。例如,以下情况如何,其中正在执行的操作相对便宜(创建 anew object和 an if statement):

少线程:

Value v;
lock (values)
{
   v = values.FirstOrDefault(a => a.Thing == someValue);
   if (v == null)
   {
      v = new Value { Thing = someValue };
      values.Add(v);
   }
}

更多线程:

Value v;
lock (values)
{
   v = values.FirstOrDefault(a => a.Thing == someValue);
}


if (v == null)
{
   v = new Value { Thing = someValue };
   lock(values)
   {
      values.Add(v);
   }
}

两种解决方案都是线程安全的,并且都非常易读(恕我直言),但是如果两者之间存在细微差别,那么将两者中更有效的一种融入我的习惯会很好。

4

2 回答 2

2

Value第二个可能会为您带来额外的性能,但实际上,只有在构造函数相对昂贵时才会成为问题。

在第二种情况下,您避免了lock过度的空检查(这非常快),而且在构造Value实例时也是如此。这可能会显着提高性能。

话虽如此,这不是线程安全的。第二个线程可以将值添加到两个锁定语句之间的代码中。因此,我推荐第一种方法(意识到您总是必须锁定values使用该集合的任何其他操作)。

如果这种查找是一种常见的查找,那么更好的方法可能是ConcurrentDictionary<T,U>改用 withThing作为键。然后,您可以使用GetOrAdd方法安全地添加或检索该值。

于 2013-10-25T20:46:11.510 回答
0

第二种情况不是线程安全的,因为当一个线程正在检查 v 是否为空时,另一个线程可能插入了一个等于 someValue 的值(正如你命名的那样)

于 2013-10-25T20:50:35.127 回答