我有一个单线程linux应用程序,我想并行。它读取数据文件,创建对象,并将它们放在向量中。然后它在每个对象上调用计算密集型方法(.5秒+)。我想与对象创建并行调用该方法。虽然我看过qt和tbb,但我对其他选项持开放态度。
我计划在向量为空时启动线程。每个人都会调用makeSolids
(下面),它有一个while循环,直到interpDone == true并且向量中的所有对象都已处理完毕。但是,在涉及线程时,我是一个n00b,我一直在寻找现成的解决方案。
QtConcurrent::map(Iter begin,Iter end,function())
看起来非常简单,但我不能在尺寸变化的矢量上使用它,是吗?我怎么告诉它等待更多的数据?
我也查看了intel的tbb,但是如果我使用parallel_for
或parallel_while
,我的主线程似乎会停止。这很糟糕,因为他们的内存管理器是推荐的(开放级联的mmgt在多线程时表现不佳)。
/**intended to be called by a thread
\param start the first item to get from the vector
\param skip how many to skip over (4 for 4 threads)
*/
void g2m::makeSolids(uint start, uint incr) {
uint curr = start;
while ((!interpDone) || (lineVector.size() > curr)) {
if (lineVector.size() > curr) {
if (lineVector[curr]->isMotion()) {
((canonMotion*)lineVector[curr])->setSolidMode(SWEPT);
((canonMotion*)lineVector[curr])->computeSolid();
}
lineVector[curr]->setDispMode(BEST);
lineVector[curr]->display();
curr += incr;
} else {
uio::sleep(); //wait a little bit for interp
}
}
}
编辑:总结一下,在主线程填充向量的同时处理向量的最简单方法是什么?
答案 0 :(得分:1)
首先,要从线程中受益,您需要为每个线程找到类似的慢速任务。你说你的每个对象处理需要.5s +,你的文件读取/对象创建需要多长时间?它可能很容易成为那个时间的十分之一或千分之一,在这种情况下,你的多线程方法将产生无法估量的好处。如果是这样的话,(是的,我会尽快回答你原来的问题)然后考虑同时处理多个对象。鉴于您的处理需要相当长的时间,线程创建开销并不是非常重要,因此您可以简单地让主文件读取/对象创建线程生成一个新线程并将其指向新创建的对象。然后主线程继续读取/创建后续对象。一旦读取/创建了所有对象,并且启动了所有处理线程,主线程就“加入”(等待)工作线程。如果这将创建太多线程(数千),则限制主线程允许获取的前端:它可能读取/创建10个对象然后加入5,然后读取/创建10,加入10,读取/创建10,加入10等直到完成。
现在,如果你真的希望read / create与处理并行,但是要序列化的处理,那么你仍然可以使用上面的方法但是在每个对象之后加入。如果你只是考虑到这种方法来设计它,这有点奇怪,但很好,因为你可以轻松地试验上面的对象处理并行性。
或者,您可以使用更复杂的方法,它只涉及主线程(操作系统在程序启动时创建),以及主线程必须启动的单个工作线程。它们应该使用互斥锁(一个确保互斥的变量,这意味着不并发,访问数据)和一个条件变量来协调,它允许工作线程有效地阻塞,直到主线程提供了更多的工作。术语 - 互斥和条件变量 - 是Linux使用的POSIX线程中的标准术语,因此应该用于解释您感兴趣的特定库。总之,工作线程等待直到主读取/创建线程向它广播一个唤醒信号,指示另一个物体已准备好进行处理。您可能希望拥有一个具有最后一个完全创建的,准备好处理的对象的索引的计数器,因此工作者线程可以保持它的已处理对象的数量,并在再次检查条件变量之前沿准备好的对象移动。
答案 1 :(得分:0)
很难说你是否一直在深思这个问题,而且你所做的事情还有很多,或者你只是在思考它,或者你是否只是担心线程问题。
读取文件并创建对象很快;一种方法很慢。依赖是每个连续的ctor取决于前一个ctor的结果 - 有点奇怪 - 但是否则没有数据完整性问题所以似乎没有任何东西需要被互斥体等保护。
为什么这比这样的更复杂(在粗伪代码中):
while (! eof)
{
readfile;
object O(data);
push_back(O);
pthread_create(...., O, makeSolid);
}
while(x < vector.size())
{
pthread_join();
x++;
}
如果你不想循环主要的连接,那么通过传递一个TID向量来产生一个线程来等待它们。
如果创建的对象/线程数是疯了,请使用线程池。或者把一个计数器作为创建循环来限制在运行连接之前可以创建的线程数。
答案 2 :(得分:0)
@Caleb:相当 - 也许我应该强调活动线程。 GUI线程应始终被视为一个。