std :: map中对象的引用是否是线程安全的?
std::map< std::string, Object > _objects;
可以从许多线程更改映射,并且此访问是同步的,但是只能从1个实例和线程访问值(Object&amp;)。是对象&amp;写的操作。如果另一个线程将项添加到地图是安全的吗?它会重新分配吗?
答案 0 :(得分:18)
C ++ 11标准保证const
方法对容器的访问对于不同的线程是安全的(即两者都使用const
方法)。
此外,[container.requirements.dataraces]陈述
实现是在内容时避免数据争用所必需的 包含在同一序列中的不同元素中的对象, 除
之外vector<bool>
换句话说,除vector<bool>
修改不同内容外,不是数据竞争。
现在,如果一个线程使另一个线程使用的迭代器无效,显然这是一个数据争用(并导致未定义的行为)。如果一个线程对容器进行非const
访问,而另一个进行const
访问,则表示数据竞争(以及未定义的行为)。 (注意:出于多线程的目的,许多函数被“视为const
”,包括begin
,end
以及非const
的其他函数(和方法)只是因为它们返回非const
迭代器。[]
包含在这组伪const
中,出于线程安全原因,map
和unordered_set
等除外 - 23.2.2.1)。
但是,如果您对容器中的元素有引用,并且参与了在另一个线程中没有使该引用无效的操作,并且从不在另一个线程中写入该元素,那么您可以安全地从中读取参考。类似地,如果其他线程甚至从未从元素读取,则写入该元素不应导致未定义的行为。
对于标准参考,17.6.5.9.5似乎保证标准库中的函数不会失控并且不必要地读/写元素。
所以简短的回答:你是安全的,只要另一个线程没有直接弄乱map
中的特定条目。
答案 1 :(得分:7)
地图中的元素是稳定的,除非从地图中删除元素,否则它们不会被移动或无效。如果只有一个线程正在写入给定对象,并且对地图本身的更改已正确同步,那么我相信它将是安全的。我确信它在实践中是安全的,我认为它在理论上也是安全的。
该标准保证不同的线程可以修改不同的元素,在[container.requirements.dataraces]中
尽管如此(17.6.5.9),当同时修改
vector<bool>
以外的同一序列中不同元素中的包含对象的内容时,需要实现以避免数据争用。
这只允许您修改元素,而不是在修改元素时将新元素插入到地图中。对于某些容器,例如std::vector
,修改向量本身也可能通过重新分配和移动它们来修改元素,但[associative.reqmts] / 9确保std::map
不会使现有元素无效。
由于访问其元素的第二个成员(即std::map
)不需要mapped_type
的成员函数,我认为[res.on.data.races] / 5表示没有其他线程会修改映射时与该成员的写入冲突。 (感谢Yakk最后一块拼图)