STL Map或HashMap是否线程安全?

5

在多线程程序中,我能否使用地图或哈希表而不需要锁定?也就是说,它们是否是线程安全的?

我想同时向地图中添加和删除内容。

似乎有很多相互矛盾的信息。

顺便说一下,我正在使用随Ubuntu 10.04附带的GCC STL库。

编辑:就像互联网上的其他信息一样,我似乎得到了相互矛盾的答案?


您需要地图实时更新的即时响应时间吗? - Simon
6
这里的所有回答基本上都说了同样的事情。 - anon
@Neil:大多数情况下都是“不行”的回答,还有一些关于并发性的谣言。 - John Dibling
没有冲突的答案,只是要小心地串起来。 - Artyom
5个回答

14

您可以安全地执行同时读取操作,即调用const成员函数。但如果其中一个涉及写入,即调用非const成员函数,则不能进行任何同时操作,并且容器的非const成员函数调用应该是独占的,不能与任何其他调用混合。

也就是说,您不能从多个线程更改容器。因此,您需要使用锁/读写锁来确保访问的安全性。


2
我认为这个答案有些令人困惑。从这个答案可以推断出,在进行一个写操作时进行多次读取是线程安全的,这是不正确的。此外,我认为你的意思是同时而不是simulations? - Naveen

5

不行。

诚实地说,不行。

编辑

好的,我会加以说明。

你可以拥有任意数量的线程读取相同的映射。这是有意义的,因为读取它不会产生任何副作用,所以无论其他人是否也在读取它都没有关系。

然而,如果你想要写入它,那么你需要获得独占访问权,这意味着防止任何其他线程在你完成之前进行写入或读取。

你最初的问题是关于并行添加和删除的。由于这两个操作都是写入操作,所以它们是否线程安全的答案是简单而明确的“不行”。


一个没有其他信息的不加限定的“不”对于在这个层次上提问的人来说,可能并不是非常有帮助。 - Nicholas Knight
你不需要阻止任何人做任何事情,你只需要确保在你写作时他们没有在读写。 - Simon
@Simon:您可以通过确保使用适当的同步构造来防止它们。 - Steven Sudit
是的,你可以。你不必这样做,但你可以这样做。 - Simon

4

2
首先,它看起来像是要收费的。我认为这是一件不好的事情。 - Steven Sudit
1
如果没有显式锁定,如何使“mymap [foo] = mymap [foo] + n;”成为线程安全的?Java放弃了线程安全库,这是有原因的! - Sjoerd
@Sjoerd。正因为这个原因,他们没有实现完全的STL接口。除此之外,它们运行得非常好。你是在谈论无锁库吗? - ronag
@ronag: Java 在最初的版本中拥有自动锁定容器。然而,他们发现 "mymap [foo] = mymap [foo] + n;" 仍需要显式锁定。因此,在容器内部添加锁定会减慢代码速度,而这并没有帮助!因此,在后来的 Java 版本中添加了新版本的容器,但不包含锁定。 - Sjoerd
.NET的ConcurrentDictionary类通过提供具有不同签名的方法(包括一些带回调函数的方法)来解决这个问题。 - Steven Sudit
显示剩余5条评论

2
STL容器线程安全最常用的模型是SGI模型:

SGI实现的STL只在以下意义上是线程安全的:访问不同容器的同时是安全的,并且对共享容器进行同时读取的访问是安全的。

但最终STL库的作者选择是否支持线程安全——据我所知,标准并没有关于STL线程安全性的规定。
但根据docs所述,在GNU的stdc++实现(gcc 3.0+)中遵循该模型需要满足一系列条件。
希望对您有所帮助。

所以你的意思是,在某些情况下可能会出现这种情况。但最好不要依赖它,对吗? - hookenz
2
@Matt:他的意思是标准并不阻止库作者使容器线程安全。一些实现会记录它们的线程安全程度,但这会有所不同。我不知道有任何默认情况下都支持多写入安全的实现。 - KeithB
@Matt:KeithB非常好地概括了答案。 - Eugen Constantin Dinca

0

答案(像大多数线程问题一样)是它大部分时间都能正常工作。不幸的是,如果在地图调整大小时捕获它,那么你将陷入麻烦。所以不行。

为了获得最佳性能,您需要一个多阶段锁。首先是读取锁,允许访问器访问,这些访问器不能修改地图,并且可以由多个线程持有(多个线程读取项目是可以的)。其次是写锁,它是独占的,允许以可能不安全的方式修改地图(添加、删除等)。

编辑 读写锁很好,但它们是否比标准互斥锁更好取决于使用模式。我无法在不知道更多信息的情况下推荐任何一种。对两者进行分析,看哪个最适合您的需求。


1
为了获得最佳性能,您根本不需要任何锁。 - Simon
+1指出允许多个读者但只有一个写者的锁可能比完整锁更好。 - Steven Sudit
@KeithB:我同意STL容器不适合进行高性能的多线程使用。为了获得最佳性能,您需要实现无锁多线程数据结构,例如http://www.codeproject.com/KB/threads/LockFree.aspx#heading0005。 - Simon
1
@丹尼尔,@史蒂文:读写锁在理论上可能很吸引人,但在实践中往往更昂贵,而且不如普通的锁扩展性好。这是因为与读写锁本身相关联的状态必须以原子方式维护,通常归结为在操作系统原语级别上锁定互斥量。因此,最终你所做的工作与一开始就使用互斥量相同。 - John Dibling
这通常归结为在操作系统原语级别上锁定互斥量。 哎?那CAS指令是用来干什么的呢? - kert
显示剩余2条评论

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