我需要在多线程环境中保护对STL容器的读取访问吗

Do I need to protect read access to an STL container in a multithreading environment?

本文关键字:STL 读取 访问 保护 多线程 环境      更新时间:2023-10-16

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

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

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

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

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

我在一个使用Visual C++6的windows环境中。

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

答案:通常情况下,必须保护读取器线程以避免出现争用情况。尽管如此,在我看来,更新中提到的一些问题还没有得到回答。

提前感谢!

谢谢大家的回答!

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

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

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

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

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

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

volatile unsigned int ContainerSize = 0;

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

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

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

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

然而,如果你需要列表的准确大小,而读者需要知道,那么除了添加和删除调用之外,你还必须在每个大小调用周围放一个关键部分。

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

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

VC++版本6中的STL不是线程安全的,请参阅最近的问题。看来你的问题有点无关紧要。即使做得很好,你仍然可能会遇到问题。

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