【问题标题】:Pointer to STL Container Thread Safety (Queue/Deque)指向 STL 容器线程安全的指针(队列/双端队列)
【发布时间】:2013-08-01 04:11:29
【问题描述】:

我目前有一个多线程难题。我有两个线程,一个读取串行数据,另一个尝试从数据中提取数据包。两个线程共享一个队列。试图创建数据包的线程有一个名为 parse 的函数,声明如下:

Parse(std::queue<uint8_t>* data, pthread_mutex_t* lock);

本质上,它需要一个指向 STL 队列的指针,并在通过队列寻找数据包时使用 pop()。使用锁是因为任何 pop() 都被锁定,并且该锁在 Parse 函数和将数据推送到队列中的线程之间共享。这样,可以在向队列中主动添加数据的同时解析队列。

代码似乎在大多数情况下都能正常工作,但我看到无效数据包的比率比我预期的要高一些。我的主要问题是我想知道当我从队列中读取数据时指针是否正在改变。例如,如果第一个线程推送一堆数据,那么在内存中找到队列的位置是否有可能发生变化?还是我保证指向队列的指针将保持不变,即使添加了数据?我担心队列的内存可以在我的 Parse() 函数期间重新分配,因此在我的函数中间,指针无效。

例如,我了解某些 STL 迭代器对于某些操作无效。但是,我传递了一个指向容器本身的指针。也就是说,像这样:

// somewhere in my code I create a queue
std::queue<uint8_t> queue;
// elsewhere...
Parse(&queue, &lock_shared_between_the_two_threads);

指向容器本身的指针是否会失效?它指向什么?第一个元素,还是...?

请注意,我不是指向任何给定元素,而是指向容器本身。另外,我从未指定应该使用哪个底层容器来实现队列,所以在这一切之下,它只是一个双端队列。

任何帮助将不胜感激。

编辑 8/1:

我能够对我的代码进行一些测试。几点:

  1. 容器本身的指针在我的程序的生命周期内不会改变。这是有道理的,因为队列本身是一个类的成员变量。也就是说,虽然队列的元素是动态分配的,但队列本身似乎并非如此。

  2. 我遇到的错误数据包似乎是我收到的串行数据的函数。我将所有数据转储到一个十六进制文件中,并且能够找到无效的数据包,并且我的算法正确地将它们标记为这样。

因此,我认为将指向 STL 容器的引用或指针传递给函数是线程安全的,但我想听听更多评论以确保是这种情况,或者这是否是实现具体的(因为很多 STL 是......)。

【问题讨论】:

  • 也许我错过了,但您push()pop() 操作中都使用lock 吗?如果没有,你应该是。
  • 对不起,是的,锁用于所有的推送和弹出操作。据我所知,这些操作不应该存在并发问题。
  • 您能否设计一个解析算法的单线程测试,以消除潜在的线程安全问题作为潜在原因?基本上,捕获大量的原始数据,构造一个队列,然后让你的解析器松动它,看看你是否有同样的问题。
  • 是的!现在我考虑了一下,在我的阅读器线程中,我可以将数据推送到十六进制转储文件。从那里,我可以在文件上使用 Parse 函数,从而打破对线程的任何依赖。
  • 当您正确实现锁定时,任何非线程安全的事情都会变得安全。听起来你有,所以我认为你怀疑线程安全是没有根据的。

标签: c++ multithreading concurrency stl


【解决方案1】:

您担心在一个线程中修改容器(添加/删除节点)会以某种方式使指向另一个线程中的容器的指针无效。容器是一种抽象,除非您删除容器对象本身,否则它将保持有效。由容器维护的数据的内存通常由stl::allocators 在堆上分配。

这与为容器对象本身分配的内存完全不同,根据容器对象本身的创建方式,可以在堆栈、堆等上。 containerallocator 的这种分离是防止对数据进行某些修改而无法修改容器对象本身的原因。

为了让调试问题更简单,就像 Jonathan Reinhart 建议的那样,让它成为一个单线程系统,读取流并解析它。

顺便说一句,您是否考虑过使用Boost Lookfree Queues 或类似的东西。它们专为此类场景而设计。如果您经常接收数据包/读取它们,锁定队列以读取/写入每个数据包可能会成为显着的性能开销。

【讨论】:

  • “除非您删除容器对象本身”,除非该对象被销毁(正如您正确提到的那样,它们也可以“在堆栈上”,但它们不会得到删除)
  • 是的。 “删除”堆栈对象肯定是not recommended :)。
猜你喜欢
  • 2013-05-21
  • 1970-01-01
  • 2015-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-25
相关资源
最近更新 更多