【发布时间】: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:
我能够对我的代码进行一些测试。几点:
容器本身的指针在我的程序的生命周期内不会改变。这是有道理的,因为队列本身是一个类的成员变量。也就是说,虽然队列的元素是动态分配的,但队列本身似乎并非如此。
我遇到的错误数据包似乎是我收到的串行数据的函数。我将所有数据转储到一个十六进制文件中,并且能够找到无效的数据包,并且我的算法正确地将它们标记为这样。
因此,我认为将指向 STL 容器的引用或指针传递给函数是线程安全的,但我想听听更多评论以确保是这种情况,或者这是否是实现具体的(因为很多 STL 是......)。
【问题讨论】:
-
也许我错过了,但您不在
push()和pop()操作中都使用lock吗?如果没有,你应该是。 -
对不起,是的,锁用于所有的推送和弹出操作。据我所知,这些操作不应该存在并发问题。
-
您能否设计一个解析算法的单线程测试,以消除潜在的线程安全问题作为潜在原因?基本上,捕获大量的原始数据,构造一个队列,然后让你的解析器松动它,看看你是否有同样的问题。
-
是的!现在我考虑了一下,在我的阅读器线程中,我可以将数据推送到十六进制转储文件。从那里,我可以在文件上使用 Parse 函数,从而打破对线程的任何依赖。
-
当您正确实现锁定时,任何非线程安全的事情都会变得安全。听起来你有,所以我认为你怀疑线程安全是没有根据的。
标签: c++ multithreading concurrency stl