昨天我问了一个问题,并得到了很多有用的反馈(谢谢!),但我认为我在这个问题上提供的信息不足-因此,我提供了另一个信息。
我有两个同时读取两个文件的线程。他们将这些文件中的信息放入两个ConcurrentQueues中。然后再出现另外两个线程,从ConcurrentQueues中取出项目,并将项目放入单个ConcurrentDictionary中。当更新字典中的项目时,线程可能必须创建一个新对象,或仅通知当前对象有更多信息进入。在后一种情况下,有时必须进行冗长的扫描。有时,在此扫描之后,对象说可以将其删除(以节省内存),然后线程将其从字典中删除。
我当前的(无效)代码如下:
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)查找时间。
有任何想法吗?抱歉,帖子很长
谢谢,
弗雷德里克
最佳答案
您可以将扫描线更改为:
DictionaryItemType dictionaryItem;
if (myConcurrentDictionary.TryGetValue(dictonaryKey, out dictionaryItem))
{
if (dictionaryItem.scan(myMessage))
这样,您可以重新检查项目是否仍在字典中,如果不是,则不进入扫描分支。
关于c# - 无法安全地锁定ConcurrentDictionary的值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4032212/