9

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

  • 一个无限期添加元素的作家线程。

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

  • 访问容器大小的几个读取器线程(通过使用 size() 方法)

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

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

更新:看起来答案还不清楚。总结主要疑问:考虑到我不需要确切的值(即我可以假设一个+/- 1 个变化)?竞争条件如何使我的 size() 调用返回无效值(即与好的值完全无关的值)?

回答: 通常,必须保护读者线程以避免竞争条件。尽管如此,在我看来,上述更新中提到的一些问题还没有得到解答。

提前致谢!

谢谢大家的答案!

4

8 回答 8

10

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

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

于 2008-10-09T14:49:21.150 回答
2

查看英特尔开源线程构建模块库提供的并发容器。在代码示例页面上的“容器片段”下查看一些示例。它们具有用于向量、哈希映射和队列的并发/线程安全容器。

于 2008-10-09T15:18:12.293 回答
1

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

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

于 2008-10-09T14:50:16.873 回答
1

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

volatile unsigned int ContainerSize = 0;

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

于 2008-10-28T10:01:17.117 回答
0

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

于 2008-10-09T14:51:27.573 回答
0

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

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

但是,如果您在读者需要知道列表时需要准确的大小,那么除了 add 和 erase 调用之外,您还必须在每个 size 调用周围放置一个关键部分。

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

聚苯乙烯。有人提到了 RW 锁,这是一件好事,尤其是当您以后想访问列表对象时。将您的互斥锁更改为 Boost::shared_mutex 将是有益的。但是,如果您调用的只是 size(),则不需要任何互斥锁。

于 2008-10-09T15:04:33.833 回答
0

VC++ 版本 6 中的 STL 不是线程安全的,请参阅这个最近的问题。所以看来你的问题有点无关紧要。即使做的一切都是正确的,你可能仍然有问题。

于 2008-10-10T15:05:42.057 回答
0

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

于 2008-10-29T03:09:27.837 回答