我是否需要在多线程环境中保护对STL容器的读访问权限?

时间:2008-10-09 14:47:05

标签: c++ multithreading visual-c++ stl concurrency

我有一个std :: list<>容器和这些线程:

  • 一个无限期添加元素的编写器线程。

  • 一个读取器/写入器线程,可在可用时读取和删除元素。

  • 访问容器SIZE的几个读取器线程(使用size()方法)

有一个普通的互斥锁可以保护前两个线程对列表的访问。我的问题是,尺寸读取器线程是否也需要获取此互斥锁?我应该使用读/写互斥?

我在使用Visual C ++ 6的Windows环境中。

更新:看起来答案尚不清楚。总结主要疑点:我是否仍然需要保护SIZE读取器线程,即使它们只调用size()(返回一个简单的变量),考虑到我不需要确切的值(即我可以假设一个+/- 1变化)?竞争条件如何使我的size()调用返回一个无效值(即一个与好的值无关)?

回答:通常,必须保护读者线程以避免竞争条件。不过,在我看来,上述更新中提出的一些问题尚未得到解答。

提前致谢!

谢谢大家的答案!

8 个答案:

答案 0 :(得分:10)

是的,读线程需要某种互斥控制,否则写会改变它下面的东西。

读写器互斥量应该足够了。但严格来说,这是一个特定于问题的问题。即使在代码中只读的const对象中,实现也可能具有可变成员。

答案 1 :(得分:2)

查看英特尔开源Threading Building Blocks库提供的并发容器。一些例子,请查看Code Samples page上的“容器代码段”。它们具有用于向量,哈希映射和队列的并发/线程安全容器。

答案 2 :(得分:1)

我不相信STL容器是线程安全的,因为没有一种很好的方法来处理跨平台的线程。对size()的调用很简单,但仍然需要保护。

这听起来像是一个使用读写锁的好地方。

答案 3 :(得分:1)

在调用时,您应该考虑某些SLT实现可能计算大小 为了克服这个问题,您可以定义一个新变量

volatile unsigned int ContainerSize = 0;

仅在已受保护的更新调用内更新变量,但您可以在没有保护的情况下读取/测试变量(考虑到您不需要确切的值)。

答案 4 :(得分:0)

是。我建议用一个强制串行访问的类来包装你的STL库。或者找一个已经调试过的类似的类。

答案 5 :(得分:0)

我要说不。在这种情况下。

如果没有互斥锁,您可能会发现size()偶尔会返回错误的值,因为会添加或删除项目。如果这是你可以接受的,那就去吧。

但是,如果您需要读者需要知道的列表的准确大小,除了添加和删除调用之外,您还必须在每个大小调用周围放置一个关键部分。< / p>

PS。 VC6 size()只返回_Size内部成员,因此没有互斥锁对于您的特定实现不会有问题,除了在添加第二个元素时它可能返回1,反之亦然。

PPS。有人提到了RW锁定,这是一件好事,特别是如果你以后想要访问列表对象的话。将您的互斥锁更改为Boost :: shared_mutex将是有益的。但是,如果您调用的所有内容都是size(),则不需要任何互斥锁。

答案 6 :(得分:0)

VC ++版本6中的STL不是线程安全的,请参阅this recent question。所以看来你的问题有点无关紧要。即使做了一切正确的事情,你仍然可能会遇到问题。

答案 7 :(得分:0)

size()是否安全(对于您提供的“安全”的定义)是依赖于实现的。即使您的平台覆盖了您的编译器版本,也就是您的线程库版本和C运行时的优化级别,请不要这样编码。它将回到你的字节,调试将是地狱。你正在为自己做好准备。