无法安全锁定 ConcurrentDictionary 的值

2024-01-05

我在锁定集合中的项目时遇到问题 - 特别是 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 是 Monitor.Enter 和 Monitor.Exit 的简写 http://www.albahari.com/threading/part2.aspx#_Locking,我尝试过这个:

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");
    }
}

两种方式都可能导致密钥未找到异常当尝试在字典中查找对象时。

有谁知道我如何找到我想要锁定的对象,然后在不被中断的情况下锁定它?抱歉 - 我是并发新手,感到非常困惑!

Thanks,

Frederik


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

这应该使你想要的成为可能,无需任何locks or Monitor usage.

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()。这会导致TryAdd失败。如果有可能,则需要做更多的工作。

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

  1. 可以凭借集合的线程安全性来完成,但是
  2. 必须单独完成,所以你打开一个窗口用于多个scan()s 在同一个对象上。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

无法安全锁定 ConcurrentDictionary 的值 的相关文章

  • 在 LINQ 中按 Id 连接多表和分组

    我想按categoryId显示列表产品的名称组 这是我的代码 我想要我的视图显示结果 Desktop PC HP Red PC Dell Yellow PC Asus Red SmartPhone Lumia 720 Blue 我的组模型
  • 错误:表达式不产生值

    我尝试将以下 C 代码转换为 VB NET 但在编译代码时出现 表达式不产生值 错误 C Code return Fluently Configure Mappings m gt m FluentMappings AddFromAssemb
  • 如何在加载.NET WinForm应用程序user.config文件时捕获异常?

    有时 在使用默认配置系统的 NET 2 0 WinForm 桌面应用程序中 user config文件将被损坏并且无法再加载 当配置系统尝试加载它时 它会抛出一个System Xml XmlException 抛开 为什么文件首先被损坏 的
  • 复制目录内容

    我想将目录 tmp1 的内容复制到另一个目录 tmp2 tmp1 可能包含文件和其他目录 我想使用C C 复制tmp1的内容 包括模式 如果 tmp1 包含目录树 我想递归复制它们 最简单的解决方案是什么 我找到了一个解决方案来打开目录并读
  • 使用 Newtonsoft 和 C# 反序列化嵌套 JSON

    我正在尝试解析来自 Rest API 的 Json 响应 我可以获得很好的响应并创建了一些类模型 我正在使用 Newtonsoft 的 Json Net 我的响应中不断收到空值 并且不确定我的模型设置是否正确或缺少某些内容 例如 我想要获取
  • 为什么 Google 测试会出现段错误?

    我是 Google Test 的新手 正在尝试提供的示例 我的问题是 当我引入失败并设置GTEST BREAK ON FAILURE 1 或使用命令行选项 GTest 将出现段错误 我正在考虑这个例子 https code google c
  • 将 Word 文档另存为图像

    我正在使用下面的代码将 Word 文档转换为图像文件 但是图片显得太大 内容不适合 有没有办法渲染图片或将图片保存到合适的尺寸 private void btnConvert Click object sender EventArgs e
  • 在 Visual Studio 2010 中从 Fortran 调用 C++ 函数

    我想从 Fortran 调用 C 函数 为此 我在 Visual Studio 2010 中创建了一个 FORTRAN 项目 之后 我将一个 Cpp 项目添加到该 FORTRAN 项目中 当我要构建程序时出现以下错误 Error 1 unr
  • qdbusxml2cpp 未知类型

    在使用 qdbusxml2cpp 程序将以下 xml 转换为 Qt 类时 我收到此错误 qdbusxml2cpp c ObjectManager a ObjectManager ObjectManager cpp xml object ma
  • 标准化 UTF-8 到底是什么?

    The 重症监护室项目 http userguide icu project org transforms normalization 现在也有一个PHP库 http us php net manual en class normalize
  • DbContext 和 ObjectContext 有什么区别

    From MSDN 表示工作单元和存储库模式的组合 使您能够查询数据库并将更改分组在一起 然后将这些更改作为一个单元写回存储 DbContext在概念上类似于ObjectContext 我虽然DbContext只处理与数据库的连接以及针对数
  • 使用自定义堆的类似 malloc 的函数

    如果我希望使用自定义预分配堆构造类似 malloc 的功能 那么 C 中最好的方法是什么 我的具体问题是 我有一个可映射 类似内存 的设备 已将其放入我的地址空间中 但我需要获得一种更灵活的方式来使用该内存来存储将随着时间的推移分配和释放的
  • C#:帮助理解 UML 类图中的 <>

    我目前正在做一个项目 我们必须从 UML 图编写代码 我了解 UML 类图的剖析 但我无法理解什么 lt
  • 如何禁用 fread() 中的缓冲?

    我正在使用 fread 和 fwrite 读取和写入套接字 我相信这些函数用于缓冲输入和输出 有什么方法可以在仍然使用这些功能的同时禁用缓冲吗 Edit 我正在构建一个远程桌面应用程序 远程客户端似乎 落后于服务器 我不知道可能是什么原因
  • 为什么 std::strstream 被弃用?

    我最近发现std strstream已被弃用 取而代之的是std stringstream 我已经有一段时间没有使用它了 但它做了我当时需要做的事情 所以很惊讶听到它的弃用 我的问题是为什么做出这个决定 有什么好处std stringstr
  • CMake 无法确定目标的链接器语言

    首先 我查看了this https stackoverflow com questions 11801186 cmake unable to determine linker language with c发帖并找不到解决我的问题的方法 我
  • “接口”类似于 boost::bind 的语义

    我希望能够将 Java 的接口语义与 C 结合起来 起初 我用过boost signal为给定事件回调显式注册的成员函数 这非常有效 但后来我发现一些函数回调池是相关的 因此将它们抽象出来并立即注册所有实例的相关回调是有意义的 但我了解到的
  • 调用堆栈中的“外部代码”是什么意思?

    我在 Visual Studio 中调用一个方法 并尝试通过检查调用堆栈来调试它 其中一些行标记为 外部代码 这到底是什么意思 方法来自 dll已被处决 外部代码 意味着该dll没有可用的调试信息 你能做的就是在Call Stack窗口中单
  • 使用 .NET Process.Start 运行时挂起进程 - 出了什么问题?

    我在 svn exe 周围编写了一个快速而肮脏的包装器来检索一些内容并对其执行某些操作 但对于某些输入 它偶尔会重复挂起并且无法完成 例如 一个调用是 svn list svn list http myserver 84 svn Docum
  • 如何从 ODBC 连接获取可用表的列表?

    在 Excel 中 我可以转到 数据 gt 导入外部数据 gt 导入数据 然后选择要使用的数据源 然后在提供登录信息后 它会给我一个表格列表 我想知道如何使用 C 以编程方式获取该列表 您正在查询什么类型的数据源 SQL 服务器 使用权 看

随机推荐