1

我有一个单线程的 linux 应用程序,我想使其并行。它读取一个数据文件,创建对象,并将它们放在一个向量中。然后它在每个对象上调用一个计算密集型方法(0.5 秒+)。我想在创建对象的同时调用该方法。虽然我看过 qt 和 tbb,但我对其他选项持开放态度。

我计划在向量为空时启动线程。每个人都会调用makeSolids(如下),它有一个 while 循环,该循环将一直运行,直到 interpDone==true 并且向量中的所有对象都已被处理。但是,在线程方面,我是 n00b,我一直在寻找现成的解决方案。

QtConcurrent::map(Iter begin,Iter end,function())看起来很简单,但我不能在大小变化的矢量上使用它,可以吗?我如何告诉它等待更多数据?

我还查看了英特尔的 tbb,但如果我使用parallel_foror ,我的主线程似乎会停止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
    }
  }
}

编辑:总而言之,在主线程填充向量的同时处理向量的最简单方法是什么?

4

3 回答 3

1

首先,要从线程中受益,您需要为每个线程找到类似的慢任务。您说您的每个对象处理需要 0.5 秒+,您的文件读取/对象创建需要多长时间?它可能很容易是那个时间的十分之一或千分之一,在这种情况下,您的多线程方法将产生微不足道的好处。如果是这种情况,(是的,如果不是,我会尽快回答您的原始问题)然后考虑同时处理多个对象。鉴于您的处理需要相当长的时间,线程创建开销并不是非常重要,因此您可以简单地让您的主文件读取/对象创建线程产生一个新线程并将其指向新创建的对象。然后主线程继续读取/创建后续对象。读取/创建所有对象后,并启动所有处理线程,主线程“加入”(等待)工作线程。如果这将创建太多线程(数千个),则限制主线程允许获得多远:它可能读取/创建 10 个对象,然后加入 5,然后读取/创建 10,加入 10,读取/创建10,加入10等,直到完成。

现在,如果您真的希望读取/创建与处理并行,但处理要序列化,那么您仍然可以使用上述方法,但在每个对象之后加入。如果您在设计时只考虑这种方法,这有点奇怪,但很好,因为您也可以轻松地试验上面的对象处理并行性。

或者,您可以使用更复杂的方法,只涉及主线程(操作系统在程序启动时创建)和主线程必须启动的单个工作线程。它们应该使用互斥锁(一个确保互斥的变量,这意味着非并发访问数据)和一个允许工作线程有效阻塞直到主线程提供更多工作的条件变量来协调。术语 - 互斥量和条件变量 - 是 Linux 使用的 POSIX 线程中的标准术语,因此应该用于解释您感兴趣的特定库。总之,工作线程一直等到主读取/创建线程向它广播一个唤醒信号,指示另一个对象已准备好进行处理。

于 2010-09-10T07:46:13.923 回答
0

很难说你是否一直在深入思考这个问题,并且还有更多的东西,或者你只是想多了,或者你只是对线程持谨慎态度。

读取文件和创建对象很快;一种方法很慢。依赖关系是每个连续的 ctor 取决于前一个 ctor 的结果 - 有点奇怪 - 但否则没有数据完整性问题,因此似乎没有任何东西需要由互斥锁等保护。

为什么这比这样的事情更复杂(在粗略的伪代码中):

while (! eof)
{
    readfile;
    object O(data);
    push_back(O);
    pthread_create(...., O, makeSolid);
}


while(x < vector.size())
{
    pthread_join();
    x++;
}

如果您不想在 main 中的连接上循环,则通过传递 TID 向量生成一个线程以等待它们。

如果创建的对象/线程的数量非常多,请使用线程池。或者放一个计数器是创建循环,以限制在加入运行线程之前可以创建的线程数。

于 2010-09-10T14:34:28.917 回答
0

@Caleb:相当——也许我应该强调活动线程。GUI 线程应始终被视为一个。

于 2010-09-13T08:10:18.597 回答