锁定/并发问题
本文关键字:问题 并发 锁定 | 更新日期: 2023-09-27 18:16:33
我有以下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行填充了' banddedgelist ',如果另一个线程修改了CicApplication的内容。banddedgecache, ' banddedgelist '的内容会无效吗?我在CicApplication中有一个锁。banddedgecache getter/setter。但我想知道我是否应该在这段代码周围放一个锁,以便CicApplication的内容。当我使用' banddedgelist '时,banddedgecache不会改变
不是自动的,但这仍然不是线程安全的。它可以抛出一个InvalidOperationException
一旦ToList
被调用,它保存这些引用的副本。但如果另一个线程修改BandEdgeCache
,而这正在发生,不好的事情发生。
因此,您应该锁定对BandEdgeCache
的所有引用。
但是沿着保存列表的行,这将是安全的,但是修改任何BandEdge
在没有一些锁定的情况下不是线程安全的。
bandEdgeList
将是一个独立的副本(因为您正在使用ToList()
),所以您不需要锁定。
但是,正如@Daniel A. White所评论的那样,您需要锁定创建该副本的LINQ语句。
在CicApplication的getter中添加锁。如果banddedgecache返回一个对集合的引用,它将无法帮助您。
CicApplication.BandEdgeCache{
get{lock(_myCollection){return _myCollection;}}
}
返回引用,但是一旦返回就退出了锁,因此在getter返回的集合的引用上使用Where()函数是在锁之外完成的,并且不是线程安全的。另一个线程可以很高兴地在Where迭代时更改集合,因为锁没有被持有——Daniel是正确的,如果另一个线程在生成列表时更改集合,将抛出InvalidOperationException。
一旦生成了列表,就可以更改原始集合,而不会影响对新列表的访问。