我正在为C#开发并发字典实现,我想知道这个GetEnumerator()
实现实际上是(线程)安全的。
它没有做一个真正的快照,所以我想知道它是否会在以后读取/写入内部字典,或者它是否会暴露潜在的死锁,因为暴露的IEnumerator
的枚举将会实际上在锁内运行。
private readonly Dictionary<TKey, TValue> internalDictionary;
private SpinLock spinLock = new SpinLock();
IEnumerator IEnumerable.GetEnumerator()
{
IEnumerator enumerator;
bool lockTaken = false;
try
{
spinLock.TryEnter(ref lockTaken);
enumerator = (this.internalDictionary as IEnumerable).GetEnumerator();
}
finally
{
if (lockTaken)
{
spinLock.Exit(false);
}
}
return enumerator;
}
答案 0 :(得分:1)
首先要想到的是,当.NET附带了线程安全的并发集合类(包括字典)时,你会想要自己创建这样的野兽。 Google System.Collections.Concurrent
了解更多信息。
我之前已经对ConcurrentDictionary类进行了基准测试,我保证它们比你自己编写的任何东西都快得多,即使使用自旋锁或Interlocked来避免任何更重的锁定机制。
在回答你的问题时,可能,但这取决于实施(这绝不是一件好事)。我猜任何写入尝试都会失败,因为标准集合类在迭代时不能被修改;但我不会依赖任何这样的机制来保证我自己的代码安全。
答案 1 :(得分:1)
对于并发编写器,您的方法不是线程安全的,因为
ToList
或实际快照。这是一个固定版本,删除了所有聪明:
IEnumerator IEnumerable.GetEnumerator()
{
lock (internalDictionary) return internalDictionary.ToList();
}
并发作家也必须采取锁定。