为什么映射在C++中不是多线程安全的

Why map is not multithread safe in C++?

本文关键字:多线程安全 映射 C++ 为什么      更新时间:2023-10-16

我在试图解决代码中的并发问题时遇到了这个问题。在原始代码中,我们只使用一个唯一的锁来锁定作为stl映射的缓存上的写操作。但是对缓存的读取操作没有限制。所以我想在读操作中添加一个共享锁,并在写操作中保留唯一锁。但有人告诉我,在映射上执行多线程是不安全的,因为它本身存在一些内部缓存问题。

有人能详细解释一下原因吗?内部缓存的作用是什么?

std::map的实现都必须满足保证:如果您的所有操作都已阅读,则无需外部同步,但只要一个线程修改,所有访问都必须同步。

我不清楚你所说的"共享锁"是什么意思;没有标准中有这样的东西。但是如果有一个线程在写,您必须确保没有其他线程可以同时读取。(可以使用类似Posix’pthread_rwlock的东西,但是标准中没有类似的东西,至少我不能找到现成的。)

至少由于C++11,标准库类上的const操作保证是线程安全的(假设对存储在其中的对象的const操作是线程安全)。

std类型的所有const成员函数都可以在C++11中从多个线程安全地调用,而无需显式同步。事实上,任何与标准库结合使用的类型(例如,作为容器的模板参数)都必须满足这一保证。

Clarificazion:该标准保证您的程序将具有所需的行为,只要您永远不会在没有同步点的情况下对同一数据位置进行写入和任何其他访问。这背后的理由是,现代CPU没有严格的顺序一致的内存模型,这会限制可扩展性和性能。在引擎盖下,编译器和标准库将在需要更强内存顺序的地方发出适当的内存围栏。

我真的不明白为什么会有任何缓存问题。。。

如果我引用映射的stl定义,那么它应该实现为二进制搜索树。

二进制搜索树只是一个具有键值节点池的树。这些节点按照其键的自然顺序进行排序,为了避免任何问题,键必须是唯一的。因此根本不需要内部缓存。

由于不需要内部缓存,读取操作在多线程环境中是安全的。但是,对于写操作,情况就不一样了,对于那些必须提供自己的同步机制的写操作,就像对于任何非线程感知的数据结构一样。

请注意,当线程执行写入操作时,您还必须禁止任何读取操作,因为此写入操作可能会导致二进制树缓慢而完全的重新平衡,即长写入操作期间的快速读取操作将返回错误的结果。