如何在 C++ 中单独锁定 unordered_map 元素
Posted
技术标签:
【中文标题】如何在 C++ 中单独锁定 unordered_map 元素【英文标题】:How to individually lock unordered_map elements in C++ 【发布时间】:2019-08-09 10:29:19 【问题描述】:我有一个unordered_map
,我希望它可以被多个线程访问,但是用互斥锁锁定整个东西会太慢。
为了解决这个问题,我在 unordered_map
的每个元素中放置了一个互斥锁:
class exampleClass
std::mutex m;
int data;
;
std::unordered_map<int,exampleClass> exampleMap;
问题是我无法安全地擦除元素,因为为了销毁互斥锁,它必须被解锁,但如果它被解锁,那么另一个线程可能会锁定它并在销毁期间写入或读取元素。
【问题讨论】:
向每个元素添加mutex
只会帮助您修改元素而不是删除它。擦除元素也是有问题的,因为您可能会修改整个 unordered_map
,这可能会干扰访问 unordered_map
的完全不相关元素的其他线程(我不是 100% 确定,但我相信没有这样的方法就无法实现它财产)。一般来说,如果你想授予只读访问不同元素的权限,你可以简单地使用shared_mutex
。
@ALX23z 对于 any 容器,只需检查删除元素是否会使迭代器和指针无效。如果是这样,您不仅需要在删除元素时排除对任何其他元素的任何访问,而且每次锁定互斥锁时还需要从容器中访问元素,而不是使用现有的迭代器。
【参考方案1】:
unordered_map
不适合细粒度并行。这是不合法的
在过程中添加或删除元素而不确保互斥。
我建议改用tbb::concurrent_hash_map
之类的东西,这将导致比锁定整个地图更少的锁定争用。 (还有其他并发哈希表实现;TBB 的优势在于它得到很好的支持和稳定。)
【讨论】:
【参考方案2】:@Sneftel 的回答已经足够好了。
但是如果你坚持使用std::unordered_map,我建议你们两个使用一个互斥锁来保护映射的插入/删除,每个元素使用另一个互斥锁来修改元素。
class exampleClass
std::mutex m;
int data;
;
std::unordered_map<int,exampleClass> exampleMap;
std::mutex mapLock;
void add(int key, int value)
std::unique_lock<std::mutex> _(mapLock);
exampleMap.insert(key, value);
void delete(int key)
std::unique_lock<std::mutex> _(mapLock);
auto it = exampleMap.find(key);
if (it != exampleMap.end())
std::unique_lock<std::mutex> _1(it->m);
exampleMap.erase(it);
如果delete
不是一个频繁的操作,这些应该对于整个地图上的大锁表现更好。
但是要小心这些类型的代码,因为它很难推理和正确。
我强烈推荐@Sneftel 的回答。
【讨论】:
如果您有彩色屏幕和眼睛(抱歉,如果您必须使用屏幕阅读器),您应该注意到delete
显示为蓝色。
我无法计算我尝试将函数命名为“register”的实例。【参考方案3】:
您有以下选择:
-
锁定整个互斥体
使用 shared_ptr 的容器,以便可以修改与容器无关的实际类(使用或不使用互斥锁)。
【讨论】:
std::shared_ptr
,就访问它指向的元素而言,与普通指针一样是线程安全的。意义 - 不是那么多。共享指针本身提供的唯一线程安全操作是控制块操作。
@Fureeish 的想法是能够锁定单个元素,同时在映射内部进行操作,如果锁定被禁止,则不会受到锁定的影响,例如,复制或移动。
那么我认为没有理由在唯一指针上使用阴影指针。而且我们缺乏确定的背景。但是,唯一的指针是默认的。以上是关于如何在 C++ 中单独锁定 unordered_map 元素的主要内容,如果未能解决你的问题,请参考以下文章