38

对 std::map 中对象的引用是线程安全的吗?

std::map< std::string, Object >   _objects;

map 可以从许多线程中更改,并且此访问是同步的,但对值(Object &)的引用只能从 1 个实例和线程访问。如果另一个线程将项目添加到地图,使用 Object & 进行写操作是否安全?它会重新分配吗?

4

2 回答 2

37

C++11 标准保证const对容器的方法访问对于不同线程是安全的(即,两者都使用const方法)。

此外,[container.requirements.dataraces] 状态

当包含对象的内容在同一序列中的不同元素中时,需要实现来避免数据竞争,除了vector<bool>

换句话说,除了vector<bool>修改不同的内容不是数据竞争。

现在,如果一个线程使另一个线程使用的迭代器无效,显然这是一场数据竞争(并导致未定义的行为)。如果一个线程不const访问容器,而另一个线程const访问,那就是数据竞争(和未定义的行为)。(注意:const出于多线程的目的,“考虑”了许多函数,包括begin,end和其他非const仅因为返回非const迭代器 的函数(和方法)。出于线程安全原因[],包含在这组伪函数中const, 除了mapunordered_set-- 23.2.2.1)。

但是,如果您对容器中的某个元素有引用,并且在另一个线程中执行不会使该引用无效的操作,并且从未在另一个线程中写入该元素,则您可以安全地从该引用中读取。同样,如果其他线程甚至从未从元素中读取,那么写入该元素不应导致未定义的行为。

对于标准参考,17.6.5.9.5 似乎保证标准库中的函数不会跑掉并不必要地读/写元素。

所以简短的回答:你是安全的,只要另一个线程不直接与map.

于 2013-02-25T12:58:36.253 回答
15

地图中的元素是稳定的,除非元素从地图中删除,否则它们不会被移动或失效。如果只有一个线程正在写入给定对象,并且对映射本身的更改正确同步,那么我相信它会是安全的。我确信它在实践中是安全的,我认为它在理论上也是安全的。

该标准保证不同的元素可以被不同的线程修改,在 [container.requirements.dataraces]

尽管有(17.6.5.9),当同时vector<bool>修改同一序列中不同元素中包含的对象的内容时,需要实现来避免数据竞争,除了 。

这仅允许您修改元素,而不是在修改元素时将新元素插入到地图中。对于某些容器,例如std::vector,修改向量本身也可能通过重新分配和移动元素来修改元素,但 [associative.reqmts]/9 确保std::map不会使现有元素无效。

由于不需要成员函数 ofstd::map来访问其元素的第二个成员(即mapped_type),我认为 [res.on.data.races]/5 表示在修改映射时没有其他线程会与对该成员的写入发生冲突。(感谢 Yakk 的最后一块拼图)

于 2013-02-25T12:43:53.550 回答