2014-02-16 36 views
2

为了避免著名的错误:我应该使用锁或ToList()

Collection was modified; enumeration operation may not execute

迭代的 IEnumerator

,我应该只使用ToList()作为this questions建议,或者我应该使用lock更新列表时?

我的问题是,ToList()只是每次都创建一个新列表,而lock只会在更新列表时在某些点上有小的延迟。

那么,我应该使用ToList()还是lock

+2

锁不起作用的情况下,列表在同一个线程上更改并且ToList不能使用列表线程安全 – Steven

+0

这是在WCF服务中,我最好检查线程。我总是对线程和WCF感到困惑。 –

+0

一般而言,Web服务可能意味着您的代码在理论上*在一个仲裁线程上被访问*。在我的Web服务中,我使用'ReadWriterLockSlim'来确保集合读取处于读取锁定状态,并且在更新时显然是写入锁定。 –

回答

3

您看到的错误告诉您,您正在尝试在枚举它时修改集合。 lock关键字适用于多线程情况,它确保只有一个线程处于关键部分。它与“锁定”收集无关,因此您可以枚举它并修改它。

您通常看到的错误与代码中出现一样,如果你有一个线程枚举集,而其他线程添加或删除收集以下

foreach(var item in items) 
{ 
    //Inside this loop now you are enumerating collection 
    //This means you can't add or delete anything from items 
    items.Add(newItem); //This will produce the error you are seeing 
} 

也可能会出现此错误。所以如果你知道你有多线程的情况,那么你可以使用lock,虽然它有点棘手,可能会影响你的并发性能,甚至会导致竞争状态。对于多线程情况,仅使用ToList可能不够,因为在调用ToList时需要确保只有一个线程可以访问集合。因此,您可能需要使用ToList以及锁定,根据您的情况,它可能会更简单。要查看如何在枚举中进行线程安全修改的示例,请参阅此答案:Making a "modify-while-enumerating" collection thread-safe

如果你知道你没有多个线程,那么ToList可能是你唯一的选择,你根本不需要lock。我还建议确定在枚举时是否确实需要修改集合。在许多情况下(但不是全部),您可以采取不同的设计,以避免它首先出现。

+0

枚举时我不修改列表,它是一个小型缓存系统,有时在阅读列表时其他函数正在调用添加方法... –

+0

这个其他函数是否在单独的线程上运行?如果是这样,请按照答案中的链接。否则,只需使用ToList,如答案中所述。 – ShitalShah