1

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

有人可以详细解释原因吗?内部缓存有什么作用?

4

4 回答 4

6

must的实现std::map都满足通常的保证:如果你所有的 do 都被读取,那么就不需要外部同步,但是一旦一个线程修改, 所有的访问都必须同步。

我不清楚“共享锁”是什么意思;标准中没有这样的东西。但是,如果任何一个线程正在写入,则必须确保没有其他线程可以同时读取。(可以使用像 Posix'pthread_rwlock这样的东西,但标准中没有类似的东西,至少不是我可以立即找到的。)

于 2013-08-22T15:24:03.683 回答
1

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

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

于 2013-08-22T15:19:06.883 回答
1

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

于 2013-08-22T15:19:43.417 回答
1

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

如果我参考地图的 stl 定义,它应该被实现为二叉搜索树

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

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

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

于 2013-08-22T15:33:23.067 回答