2011-12-02 71 views
3

我有下面的C#代码:锁定/并发问题

1. List<BandEdge> bandEdgeList; 
2.  
3. bandEdgeList = CicApplication.BandEdgeCache.Where(row => row.Coater == coater).ToList(); 
4. foreach (BandEdge bandEdge in bandEdgeList) 
5.  { 
6.   ... 
7.   ... 
8.  } 

我的问题是这样的。一旦在第3行填充了“bandEdgeList”,如果另一个线程修改了CicApplication.BandEdgeCache的内容,“bandEdgeList”的内容是否会失效?我在CicApplication.BandEdgeCache getter/setter中有一个锁。但是我想知道是否应该锁定这段代码,以便在使用'bandEdgeList'时CicApplication.BandEdgeCache的内容不会改变。

+0

如果'BandEdgeCache'是一个可编辑的收集,以及,你可以有效地丢失在您的本地列表中的项目,可以有一个不符合你的'Coater'条件,或者可以在列表不再在项目BandEdgeCache'集合以及下面答案中的问题。 – Marc

回答

5

不自动,但这仍然不是线程安全的。它可能会抛出一个InvalidOperationException

一旦ToList被调用,它节省了这些引用的副本。但是如果另一个线程修改BandEdgeCache,那么就会发生不好的事情。

因此,您应该锁定所有对BandEdgeCache的引用。

但是随着保存列表的线,这将是安全的,但修改任何BandEdge是不是线程安全没有一些锁定。

3

bandEdgeList将是一个独立副本(因为您使用的是ToList()),所以您不需要锁定。

然而,随着@Daniel A.怀特评价说,需要围绕创建副本中的LINQ声明锁定。

+1

这将是一个独立的副本,但为了做到这一点,需要锁定“BandEdgeCache”。 –

+0

我今天学到了一些东西......我以为ToList实际上并没有制作副本,而你必须使用ToArray才能复制......感谢Oded。 –

+1

@jsobo - 它只复制引用。 –

1

在CicApplication.BandEdgeCache的吸气把锁并不能帮助你,如果它返回到集合的引用。

CicApplication.BandEdgeCache{ 
    get{lock(_myCollection){return _myCollection;}} 
} 

返回引用,但已经退出锁一旦返回所以使用上,参照getter返回集合中凡()函数超出了锁完成,不是线程安全的。另一个线程可以非常高兴地改变集合,而Where迭代是因为锁没有被持有 - Daniel是正确的,如果在生成列表时另一个线程改变集合,则会抛出InvalidOperationException。

一旦生成列表,可以更改原始集合,而不会损害对新列表的访问。