C# 是否可以安全地从泛型集合获取计数值,而不锁定集合?

C# 是否可以安全地从泛型集合获取计数值,而不锁定集合?,c#,.net,multithreading,.net-3.5,locking,C#,.net,Multithreading,.net 3.5,Locking,我有两个线程,一个生产者线程将对象放入通用列表集合,另一个消费者线程将这些对象从同一个通用列表中拉出。我已经使用lock关键字正确同步了对集合的读取和写入,并且一切正常 我想知道的是,在不首先锁定集合的情况下访问Count属性是否可以 JaredPar将Count属性称为可导致竞争条件的决策过程,如下所示: if (list.Count > 0) { return list[0]; } 如果列表中有一个项目,并且该项目在访问Count属性之后但在索引器之前被删除,则会发生异常。我

我有两个线程,一个生产者线程将对象放入通用列表集合,另一个消费者线程将这些对象从同一个通用列表中拉出。我已经使用lock关键字正确同步了对集合的读取和写入,并且一切正常

我想知道的是,在不首先锁定集合的情况下访问Count属性是否可以

JaredPar将Count属性称为可导致竞争条件的决策过程,如下所示:

if (list.Count > 0)
{
    return list[0];
}
如果列表中有一个项目,并且该项目在访问Count属性之后但在索引器之前被删除,则会发生异常。我明白了

但是,使用Count属性来确定一个完全不同的集合的初始大小,可以吗?实例成员不保证线程安全,所以我应该在访问Count属性之前锁定集合吗?

我怀疑它是“安全的”,因为“不会导致任何灾难性的错误”—但您可能会得到过时的数据。这是因为我怀疑它只是保存在一个简单的变量中,将来可能会是这样。但这和保证不一样

就我个人而言,我会保持简单:如果要访问共享的可变数据,只能在锁中访问(对相同的数据使用相同的锁)。如果你有适当的隔离(因此你知道你有适当的内存屏障,你知道你永远不会在一个线程中修改它,而你在另一个线程中读取它),那么无锁编程是非常好的,但听起来这里不是这样的


好消息是,获得一个无争议的锁非常便宜——所以如果我是你,我会选择安全的路线。如果不引入竞争条件,线程就已经足够难了,因为竞争条件可能不会带来显著的性能优势,但会导致罕见的、不可生产的bug。

@Jon Skeet:伙计,我很高兴你能参与进来!在这种情况下,过时的值完全可以,因为它只是用来确定另一个集合的“粗略”初始大小。我负担不起的是Count属性返回负值或非常大的值。如果在我提取计数值的同时,另一个线程正在修改集合,是否可能发生这种情况?Count是一个int,所以即使它被修改了,它也会以原子的方式完成,对吗?@Matt:我希望这一切都会好起来,但我还是会在自己的代码中保证安全。您将依赖于在以后的版本中可能会更改的实现细节。是的,它可能只是存储在一个简单的
int
变量中,但您真的想依赖它吗?您关心的是性能还是代码的简单性?如果您使用C#3并锁定集合本身,则可以创建一个扩展方法(“LockedCount()”或类似的方法)以使其更简单。@Jon Skeet:没错。如果不能保证其当前和未来的实施,猜测是不明智的。非常感谢@JonSkeet LockedCount,好主意,已经在我的项目中实施了