多线程访问一个 std::map 会导致不安全的行为吗?
Posted
技术标签:
【中文标题】多线程访问一个 std::map 会导致不安全的行为吗?【英文标题】:Mutithreading accessing one std::map , will cause unsafe behavior? 【发布时间】:2012-09-04 03:10:34 【问题描述】:如果多个线程访问一个映射对象,但是,我可以确保这些线程中的任何一个访问都不会具有相同的键,并且访问就像:
//find value by key
//if find
// erase the object or change the value
//else
// add new object of the key
操作会不会导致同步问题?
【问题讨论】:
【参考方案1】:是的,在没有正确同步的情况下进行并发更新可能会导致崩溃,即使您的线程访问不同的键:std::map
基于树,树会重新平衡,因此您可能会导致写入具有看似无关的键。
此外,在写入的同时执行只读访问,或者搜索解锁+写入锁定是不安全的:如果您有可能更新或删除节点的线程,则必须在写入之前锁定所有读取器。
【讨论】:
谢谢!您的回答让我对这个问题更清楚了。【参考方案2】:如果任何线程插入到树中,您将遇到并发问题。 STL map
是使用红黑树实现的(或者至少这是我所熟悉的——我不知道标准是否要求红黑树)。红黑树可能会在插入时重新平衡,这将导致线程之间的各种竞争。
只读访问权限(绝对 no 写入器)可以,但请记住 operator[]
是非只读的;它可能会添加一个新元素。您需要使用 find()
方法,获取迭代器,然后自行解除引用。
【讨论】:
谢谢!看来我必须加同步锁才能防止出现问题。 C++11 并没有强制要求底层数据结构(尽管很多人可能会这么想,但 ISO C 要求qsort
是一个快速排序)但是地图是 非常经常以红黑的身份出现。【参考方案3】:
除非文档(即 ISO C++11 标准)说它是线程安全的(而他们不是),否则就是这样。时期。它不是线程安全的。
可能有 实现 std::map 允许这样做,但它绝不是可移植的。
地图通常建立在红黑树或其他自动平衡数据结构上,因此对结构的修改(例如插入或删除键)将导致重新平衡。
您应该使用诸如互斥信号量之类的东西来包装地图上的读取和写入操作,以确保正确完成同步。
【讨论】:
以上是关于多线程访问一个 std::map 会导致不安全的行为吗?的主要内容,如果未能解决你的问题,请参考以下文章
std::map 访问线程是不是安全,如果它的迭代器永远不会失效
如何以线程安全的方式使用`std::unordered_map`?