【发布时间】:2010-10-26 15:51:27
【问题描述】:
我无法锁定 Collection 中的项目 - 特别是 ConcurrentDictionary。
我需要接受一条消息,在字典中查找该消息,然后对其进行长时间扫描。由于程序占用大量内存,扫描后对象返回 true 如果他们认为是删除它的好时机(我通过从字典中删除它来做到这一点)。但是,另一个线程可能会在类似的时间出现,并在删除后立即尝试访问同一个对象。这是我的第一次尝试:
string dictionaryKey = myMessage.someValue;
DictionaryObject currentObject = myConcurrentDictionary.GetOrAdd(dictionaryKey, new DictionaryObject());
// we can be interrupted here
lock (currentObject)
{
//KeyNotFoundException is possible on line below
if (myConcurrentDictionary[dictonaryKey].scan(myMessage)) // Scans the message - returns true if the object says its OK to remove it from the dictionary
{
DictionaryObject temp; // It's OK to delete it
if (!queuedMessages.TryRemove(ric, out temp)) // Did delete work?
throw new Exception("Was unable to delete a DictionaryObject that just reported it was ok to delete it");
}
}
但是,上述方法不起作用 - 一个线程可能会在另一个线程尝试访问字典中的对象之前从字典中删除一个对象。在阅读了lock is shorthand for Monitor.Enter and Monitor.Exit 之后,我尝试了这个:
string dictionaryKey = myMessage.someValue;
Monitor.Enter(GetDictionaryLocker);
DictionaryObject currentObject = myConcurrentDictionary.GetOrAdd(dictionaryKey, new DictionaryObject());
// we can be interrupted here
lock (currentObject)
{
Monitor.Exit(GetDictionaryLocker);
//KeyNotFoundException is still possible on line below
if (myConcurrentDictionary[dictonaryKey].scan(myMessage)) // Scans the message - returns true if the object says its OK to remove it from the dictionary
{
DictionaryObject temp; // It's OK to delete it
if (!queuedMessages.TryRemove(ric, out temp)) // Did delete work?
throw new Exception("Was unable to delete a DictionaryObject that just reported it was ok to delete it");
}
}
尝试在字典中查找对象时,这两种方法都可能导致 KeyNotFoundException。
有谁知道我怎样才能找到我想锁定的对象,然后将其锁定而不会被打断?抱歉 - 我是并发新手,感到非常困惑!
谢谢,
弗雷德里克
【问题讨论】:
-
我认为您不必为 ConcurrentDictionary 添加自定义锁定?它是线程安全的吗?
-
Hi Dismissile,是的,它是线程安全的,但是查找我想要的密钥然后实际获取我的锁的操作不是。
-
@Dissimilie - 你是对的,这里的问题是没有办法自动检索对象并将其标记为“正在处理”以避免并发
scan()s。 -
也许你会选择
ConcurrentQueue<>?ConcurrentDicrionary<>适合映射。所以出列下一个工作(处理)项目并处理它。如果您在处理之前需要一些映射,然后映射工作项(但它已经超出处理队列,所以没有并发问题)
标签: c# .net multithreading concurrency c#-4.0