是否返回IEnumerable 线程安全?

我有一个Visual Studio 2008 C#.NET 3.5项目,我希望有一个线程安全的Foo对象池。

 public class FooPool { private object pool_lock_ = new object(); private Dictionary foo_pool_ = new Dictionary(); // ... public void Add(Foo f) { lock (pool_lock_) { foo_pool_.Add(SomeFooDescriminator, f); } } public Foo this[string key] { get { return foo_pool_[key]; } set { lock (pool_lock_) { foo_pool_[key] = value; } } } public IEnumerable Foos { get { lock (pool_lock_) { // is this thread-safe? return foo_pool_.Select(x => x.Value); } } } } 

public IEnumerable Foos { get; } 函数线程安全吗? 或者,我是否需要克隆结果并返回新列表?

不,不是。

如果在调用者枚举时另一个线程添加到字典中,则会出现错误。

相反,你可以这样做:

 lock (pool_lock_) { return foo_pool.Values.ToList(); } 

IEnumerable Foos { get; } 函数线程安全吗?

没有。

或者,我是否需要克隆结果并返回新列表?

不,因为那也不对。 给出错误答案的线程安全方法不是很有用。

如果您锁定并制作副本,那么您要返回的内容就是过去的快照 。 在释放锁定时 ,可以将集合更改为完全不同。 如果你通过复制使这个线程安全,那么你现在正在把一个充满谎言的包交给你的来电者。

当你处理单线程代码时,一个合理的模型就是一切都保持不变,除非你采取具体的措施来改变一件事。 这在multithreading代码中不是一个合理的模型。 在multithreading代码中,您应该采取相反的观点:除非您采取特定措施(例如锁定)以确保事情不会发生变化,否则一切都在不断变化。 数百纳秒之前发布一系列描述世界遥远的世界状态的Foos有什么好处? 在这段时间内,整个世界可能会有所不同。

不是线程安全的。 你需要返回ToList()

 return foo_pool_.Select(x => x.Value).ToList(); 

小心推迟执行!

事实是在锁退出后实际的代码运行

 // Don't do this lock (pool_lock_) { return foo_pool_.Select(x => x.Value); // This only prepares the statement, does not run it } 

你可能想要考虑一个SynchronizedCollection,

SynchronizedCollection类提供线程安全的集合,其中包含generics参数指定的类型的对象作为元素。

http://msdn.microsoft.com/en-us/library/ms668265.aspx

如果您锁定每次读取访问权限,您将以非常糟糕的性能结束。 并且在使用toList的建议中,您还将每次分配内存。

如果您使用.NET 4,只需使用新线程安全集合中的ConcurrentDictionary类。 它们将提供非常快速(无锁)的机制,用于从多个线程访问数据。

http://msdn.microsoft.com/en-us/library/dd997305.aspx

如果您使用的是旧的.NET版本,我建议您使用带有count变量的循环而不是foreach,如果您只添加元素而不删除它们,它将起作用(如您的示例中所示)