gpt4 book ai didi

c# - 无法安全地锁定 ConcurrentDictionary 的值

转载 作者:行者123 更新时间:2023-11-30 22:43:18 24 4
gpt4 key购买 nike

我在锁定集合中的项目时遇到问题 - 特别是 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

有谁知道我怎样才能找到我要锁定的对象然后锁定它而不被打扰?抱歉 - 我是并发方面的新手,感到非常困惑!

谢谢,

弗雷德里克

最佳答案

您应该在开始扫描之前从字典中删除该对象,以防止任何其他线程尝试并发使用它。如果以后需要,在 scan() 失败后,您可以随时将其重新添加。 remove 和 add 都保证在这个并发集合上是线程安全的。

这应该可以在没有任何lockMonitor 用法的情况下实现您想要的。

string dictionaryKey = myMessage.someValue;

DictionaryObject currentObject = null;
if (myConcurrentDictionary.TryRemove(dictionaryKey, out currentObject))
{
//KeyNotFoundException is possible on line below
if (!currentObject.scan(myMessage)) // Scans the message - returns true if the object says its OK to remove it from the dictionary
{
if (!myConcurrentDictionary.TryAdd(dictionaryKey, currentObject))
throw new Exception("Was unable to re-insert a DictionaryObject that is not OK for deletion");
}
}

我担心的是,在不理解您的其余代码的情况下,其他线程是否可以在您调用 scan() 期间使用相同的 key 添加回另一条消息。这将导致 TryAdd 失败。如果这是可能的,则需要做更多的工作。

您当前模型的问题是,即使集合是线程安全的,如果您希望将“正在扫描”的项目留在集合中,您真正必须做的是执行以下操作组合 原子地:1. 找到一个免费项目,然后 2. 将其标记为“正在使用”。

  1. 可以通过线程安全的集合来完成,但是
  2. 必须单独完成,因此您需要为同一对象上的多个 scan() 打开一个窗口。

关于c# - 无法安全地锁定 ConcurrentDictionary 的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4025428/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com