我有一个std :: list<>容器和这些线程:
一个无限期添加元素的编写器线程。
一个读取器/写入器线程,可在可用时读取和删除元素。
访问容器SIZE的几个读取器线程(使用size()方法)
有一个普通的互斥锁可以保护前两个线程对列表的访问。我的问题是,尺寸读取器线程是否也需要获取此互斥锁?我应该使用读/写互斥?
我在使用Visual C ++ 6的Windows环境中。
更新:看起来答案尚不清楚。总结主要疑点:我是否仍然需要保护SIZE读取器线程,即使它们只调用size()(返回一个简单的变量),考虑到我不需要确切的值(即我可以假设一个+/- 1变化)?竞争条件如何使我的size()调用返回一个无效值(即一个与好的值无关)?
回答:通常,必须保护读者线程以避免竞争条件。不过,在我看来,上述更新中提出的一些问题尚未得到解答。
提前致谢!
谢谢大家的答案!
答案 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运行时的优化级别,请不要这样编码。它将回到你的字节,调试将是地狱。你正在为自己做好准备。