我正在使用intel TBB实现一种bitonic排序。使用 parallel_invoke 方法时一切顺利。但是当使用task_group(不调用wait方法)时,输出不会被排序。当如下使用task_group时,程序不会终止。
void bitonic_merge(bool up, int array[],int size){
if(size==1){
return;
}
int m = greatestPowerOfTwoLessThan(size);
bitonic_compare(up, array, size - m, m);
g->run(Bitonic_Merge(up, array , m));
g->run(Bitonic_Merge(up, &array[m],size - m));
g->wait();
return;
}
有人能看出什么问题吗? parallel_invoke和使用task_group有什么区别?还有什么比这种情况更好用? parallel_invoke 或 task_group ?或者我应该使用其他方法吗?
提前致谢
答案 0 :(得分:4)
程序没有终止,因为它已死锁。你的代码非常接近正确,但问题是'g'是一个指向task_group的全局指针,你进行递归任务分解,这不是一个混合得很好的组合。
如果你闯入调试器,我希望你会在task_group :: wait中看到很多线程,等待任务完成。
任务没有完成,因为你在线程和任务中共享你的task_group,而且他们都在有效地等待彼此。
要解决此问题,请在bitonic_merge函数内的堆栈上声明task_group(或structured_task_group),这仍然允许在等待调用期间调度和执行任务,就像使用parallel_invoke一样,但是因为task_group不是'在任务之间共享,等待调用将在所有子任务完成后完成并避免死锁。
请注意,我在msdn论坛上为PPL回答了similar question with a performance slant并记住了task_group,structured_task_group,parallel_invoke和parallel_for / parallel_for_each的语法和语义在PPL和TBB之间是一致的。使用对你或你的平台有意义的东西。
答案 1 :(得分:0)
如果子问题的数量不变,请使用tbb :: parallel_invoke。 否则使用递归和task_group。 由于子问题的数量是2,因此parallel_invoke适合并且更容易实现。
有关详细信息,请参阅英特尔TBB设计模式
答案 2 :(得分:0)
在这里等待任务组非常重要。如果没有wait(),函数将在完成task_group :: run()完成的递归“调用”之前返回,显然它会破坏算法。 parallel_invoke确实适用,并且它会自动等待“调用”函数完成,因此更易于使用。 是什么让我(作为TBB开发人员)担心的是为什么给定的程序片段不会终止。就我所知,它应该运作良好。你介意提交一个完整的程序源(在这里或the TBB forum?)