昨天我问了一个关于这个的问题并得到了很多有用的反馈(谢谢!)但我认为我没有在问题中提供足够的信息 - 因此,另一个。
我有两个同时读取两个文件的线程。他们将这些文件中的信息放入两个ConcurrentQueues中。然后出现另外两个线程,将ConcurrentQueues中的项目出列,并将项目放入单个ConcurrentDictionary中。更新Dictionary中的项目时,线程可能必须创建一个新对象,或者只是通知当前对象有更多信息进入。在后一种情况下,有时需要进行冗长的扫描。有时,在此扫描之后,对象表示可以删除它(作为保存内存的尝试),并且线程将其从Dictionary中删除。
我目前的(破损)代码如下:
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 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");
}
}
这是怎么回事:
在字典中找到我想要的对象之间:
DictionaryObject currentObject = myConcurrentDictionary.GetOrAdd(dictionaryKey, new DictionaryObject());
然后锁定该对象:
lock (currentObject)
,线程可以被中断,所以当我在这里试图访问它时,另一个线程有可能将对象从字典中删除:
if (myConcurrentDictionary[dictonaryKey].scan(myMessage))
然后会导致 KeyNotFoundException 。我需要一些以原子方式锁定对象的方法。
正如我所说,我昨天得到了一些建议,但我不明白我怎么能用它们
Threading.Interlocked.CompareExchange
,我可以用它来标记该对象是“正在使用中”。但我不知道如何处理正在使用的对象的情况 - 我将如何等待呢?我有一些限制:我必须按顺序处理ConcurrentQueues,所以我不能放弃在Dictionary中放置一个对象,或者稍后再回来 - 我需要阻止它。字典可能包含500,000个或更多项,所以我真的需要ConcurrentDictionary的O(1)查找时间。
有什么想法吗?对于长篇文章感到抱歉
谢谢,
弗雷德里克
答案 0 :(得分:1)
您可以将扫描线更改为:
DictionaryItemType dictionaryItem;
if (myConcurrentDictionary.TryGetValue(dictonaryKey, out dictionaryItem))
{
if (dictionaryItem.scan(myMessage))
通过这种方式,您可以重新检查项目是否仍在字典中,如果不存在,则不要进入扫描分支。