C++11 STL容器与线程安全性

51

我很难找到关于此事的最新信息。

C++11版本的STL容器是否保证了一定程度的线程安全?

考虑到性能问题,我不认为它们会有,但另一方面,这就是我们拥有 std::vector::operator[]std::vector::at 的原因。


2
我的猜测是,边界检查与互斥锁等操作在性能方面完全不同。但我可能错了。 - Constantinius
8
在容器访问层面上的线程安全通常是无用的,因为你想要编写像是“cash[i] = cash[i] + total”这样的代码,而且锁定需要在容器本身以上的更高级别处进行。 - jcoder
2
一个相关问题 安全的并行只读访问STL容器 - Bo Persson
4
有相当多的保证(在 [res.on.data.races]、[container.requirements.dataraces] 以及前置章节 [intro.multithread] 中)。@Mr.C64 的回答非常到位,如果你需要更具体的答案(可能包含标准引用),请调整问题。 - avakar
@avakar 如果您能为引用制作一个答案,那将是非常好的。我有标准答案,但关闭问题并提供详尽的答案会更好。 - Šimon Tóth
3个回答

49

由于现有的回答没有涵盖它(只有一个评论),因此我将提到当前C ++标准规范的23.2.2 [container.requirements.dataraces],其中说:

当在同一个序列中不同元素的包含对象的内容被同时修改时(除了vector<bool>),实现必须避免数据竞争。

也就是说,安全地访问同一容器的不同元素是安全的,例如,您可以拥有一个全局的std::vector<std::future<int>>,其中包含十个元素,并且有十个线程,每个线程都写入向量的不同元素。

除此之外,与标准库的其余部分相同的规则适用于容器(请参见17.6.5.9 [res.on.data.races]),正如Mr.C64的回答所述,另外[container.requirements.dataraces]列出了一些容器的非const成员函数,可以安全地调用它们,因为它们仅返回对元素的非const引用,它们实际上不会修改任何东西(通常任何非const成员函数都必须被认为是修改。)


32

我认为STL容器提供以下基本的线程安全保证:

  • 同一对象的同时读取是可以的。

  • 不同对象的同时读/写操作是可以的。

但如果你想进行其他操作,例如对同一个对象进行同时写入,那么就必须使用某种形式的自定义同步(例如关键区域)。


12
在这个上下文中,“object”的意思是“元素”还是“容器”? - Šimon Tóth
例如,在不同的线程中同时执行myvec[0] = 0myvec[1]是可以的吗?如果“对象”是容器,那么这就是对同一对象的读写操作,但如果“对象”是元素,则不是。您还可以将容器想象成一个伸展树,其中对容器的同时读取是不允许的,但是如果有保证同时读取是可以的,那么std::map不能被实现为在这方面不安全的伸展树。 - Steve Jessop
@Let_Me_Be: 在这种情况下,“object”等同于“容器”。 - Mr.C64
5
@SteveJessop,当同时进行 myvec[1] 操作时,myvec[0] = 0 可能会出现问题。对于顺序容器的 operator[] 操作必须避免数据竞争([container.requirements.dataraces]/1)。但这并不适用于无序和关联式容器。 - avakar
2
@JonathanWakely,我基于n3337/23.2.2/1进行了这个:为避免数据竞争(17.6.5.9),实现应将以下函数视为const:begin、end、[...]以及除关联或无序关联容器之外的operator[]。 - avakar
显示剩余3条评论

-6

不要使用STL容器,而是尝试使用PPL或Intel TBB进行线程安全容器操作。

正如其他人所指出的那样,它们具有通常的“多读线程安全性”,但这甚至在C++11之前就已经存在了。当然,这并不意味着单个写入者多个读取者。它意味着没有写入者。 :)


1
但那甚至是在C++11之前。不,它不是。C++03甚至不知道什么是线程。因此,它不指定处理线程的行为。 - Nicol Bolas
他没有询问编译器如何实现标准。他关心的是标准提供了什么"保证"; 因此,实现提供的"保证"是无关紧要的。 - Nicol Bolas
7
实际上,“最重要的前两个字符”是错误的,因为其他答案已经清楚地表明确实有某种程度的线程安全性保证,即使只是对于同时读取而没有任何写入,或者特定的函数。因此,一个明确的“否定”太过笼统,无法在任何方面正确。 - Christian Rau
我认为多个读者并不值得注意(尽管我很久以前就添加了这个功能,以免人们感到困惑,直到有人在评论中抱怨)。但是也许我不像普通的开发者那样(从某种意义上说,我认为读取安全性是微不足道的 - 请参见我的第一条评论)。 - NoSenseEtAl
4
@NoSenseEtAl:“我认为多个读者并不值得注意。” 但他没有问你认为什么值得注意。他要求事实:“C++11版本的STL容器是否有一定程度的线程安全性保证?” 事实上的答案是“是的”,因为标准确实有一定程度的保证。 - Nicol Bolas
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接