如何在 C++ 中的 unordered_map 的并发读取和锁定单线程写入之间交替

Posted

技术标签:

【中文标题】如何在 C++ 中的 unordered_map 的并发读取和锁定单线程写入之间交替【英文标题】:How to alternate between concurrent reads and locked single-thread writes to unordered_map in C++ 【发布时间】:2017-10-25 01:11:06 【问题描述】:

我有一个应用程序,我想在其中跨多个线程记忆函数的结果。我想要的代码的单线程版本如下所示:

int memoized_method(int arg) 
   int result;
   if (memo.count(arg)) 
       result = memo[arg];
   
   else 
       result = unmemoized_method(arg);
       memo[arg] = result;
   
   return result;

其中memounordered_map。据我了解,unordered_map 为并发读取和单线程写入提供了保证。我的挑战是,理想情况下,我需要在这些模式之间交替。这使得获得多线程代码的全部优势变得具有挑战性。

我将提供代码以使困境更加清晰。我可以像这样使用mutex

mutex mtx;

int memoized_method(int arg) 
   int result;
   mtx.lock();
   if (memo.count(arg)) 
       result = memo[arg];
   
   else 
       result = unmemoized_method(arg);
       memo[arg] = result;
   
   mtx.unlock();
   return result;

我不想要这个选项,因为每次我访问备忘录时它都需要关键锁,这会大大降低我的特定应用程序的速度。或者,我可以这样做:

mutex mtx;

int memoized_method(int arg) 
   int result;
   if (memo.count(arg)) 
       result = memo[arg];
   
   else 
       mtx.lock();
       result = unmemoized_method(arg);
       memo[arg] = result;
       mtx.unlock();
   
   return result;

但这不是线程安全的,因为memo 最终可能会在其他线程正在访问它时重新散列。

基本上,我希望能够仅在线程位于“else”部分时锁定对代码“if”部分的访问。我还需要能够让“if”块中的任何线程在它被锁定时完成它。我看不到使用mutex 解决此问题的方法,因为mutex 与一个特定的代码块相关联。有没有我没有注意到的棘手方法?或者还有其他我应该注意的锁类型吗?

【问题讨论】:

您是否针对特定平台? 它必须在 Linux 和 Mac 上工作 【参考方案1】:

您有一个经典的readers-writers problem,其中多个线程可以同时读取,但一次只能写入一个线程,并且一个线程正在写入时没有线程可以读取。

我认为 C++ 中读写器锁的“最佳”解决方案现在是 C++17's std::shared_mutex,您可以在写入路径中以独占模式锁定,在读取路径中以共享模式锁定。它就是为这个问题而设计的。您还需要一个条件变量来让完成阅读器唤醒待处理的作者,反之亦然。

您还绝对希望将计算保持在临界区之外。

如果你不能使用std::shared_mutex,Reader/Writer Locks in C++和How would you implement your own reader/writer lock in C++11?还有很多其他的解决方案。

【讨论】:

以上是关于如何在 C++ 中的 unordered_map 的并发读取和锁定单线程写入之间交替的主要内容,如果未能解决你的问题,请参考以下文章

C++ 哈希表 - 如何解决 unordered_map 与自定义数据类型作为键的冲突?

如何在 C++ 中单独锁定 unordered_map 元素

c++ 中的 map 和 unordered_map 在内存使用方面有啥区别吗?

c++ unordered_map 碰撞处理,调整大小和重新散列

unordered_map 中的 C++ 线程(无复制构造函数)

std::unordered_map 如何表现? [C++]