线程构建块分段错误
Thread Building Blocks segmentation fault
我正在尝试使用英特尔线程构建模块调试 C++ 代码,按照此处的过程 - Debugging in threading building Blocks。
我用一个线程尝试了 运行 代码,并将 TBB_USE_DEBUG 设置为 1(我在这里问了一个关于它的先前问题 - )。但是,我遇到了一个奇怪的分段错误。这是 gdb 回溯。
#0 0x00007ffff793fbc1 in ?? () from /usr/lib/x86_64-linux-gnu/libtbb.so.2
#1 0x000000000040d2cb in tbb::task::spawn_and_wait_for_all (child=..., this=0x7ffff63b7a40)
at /usr/include/tbb/task.h:728
#2 MpsTask1::execute (this=0x7ffff63b7a40)
at /capps/mps_implementations.hpp:102
#3 0x00007ffff793ffdd in ?? () from /usr/lib/x86_64-linux-gnu/libtbb.so.2
#4 0x000000000040d2cb in tbb::task::spawn_and_wait_for_all (child=..., this=0x7ffff63b7d40)
at /usr/include/tbb/task.h:728
#5 MpsTask1::execute (this=0x7ffff63b7d40)
at /capps/mps_implementations.hpp:102
我对这个回溯感到很困惑,因为我无法控制库中发生的事情。有没有可能是我犯的错误导致 spawn_root_and_wait 失败?
这是我的代码(没有构造函数和析构函数以保持简短)。其目的是通过归约运算计算数组的最大前缀和。它递归地划分数组,直到块足够小,然后加入结果。我知道我可以使用 TBB parallel_reduce 模板来解决这个问题,但我的目标是了解基于 TBB 任务的编程是如何工作的。
class MpsTask1: public task {
public:
task* execute(){
if(size <= Cutoff){
for(int i = left; i != right; i++){
*sum = *sum + array[i]);
if (*sum <= *mps){
*mps = *sum;
*position = i+1;
}
}
memo[depth][index] = cutoff;
}else{
// Parameters for subtasks
int middle = (right+left)/2;
int sizel = middle - left;
int sizer = right - middle;
int newDepth = depth + 1;
int lIndex = 2*index;
int rIndex = lIndex + 1;
// Variables for results
int lPos = left;
int rPos = middle;
double lsum, rsum, lmps, rmps;
// Create subtasks
set_ref_count(3);
MpsTask1& lTask = *new(allocate_child()) MpsTask1(Cutoff,array,sizel,&lsum,&lmps,&lPos,memo,newDepth,lIndex,left,middle);
spawn(lTask);
MpsTask1 &rTask = *new(allocate_child()) MpsTask1(Cutoff,array,sizer,&rsum, &rmps,&rPos,memo,newDepth,rIndex,middle,right);
spawn_and_wait_for_all(rTask);
// Join results
rmps = lsum+rmps;
*sum = lsum+rsum;
if(*mps <= rmps){
*mps = rmps;
*position = rPos;
memo[depth][index] = rightChild;
}
else{
*mps_interval = lmps;
*position = lPos;
memo[depth][index] = leftChild;
}
return NULL;
}
}
private:
/* Below this size, the mps and sum are computed sequentially */
int Cutoff;
/* Input array and its size */
double* array;
int size;
/* Identification of the task */
int depth;
int index;
int left;
int right;
/* Intervals for sum and mps */
double* sum;
double* mps;
/* Position of the mps */
int* position;
// Status : left child, right child, or cutoff
Status** memo;
};
void parallel_mps(double* array, int size, int Cutoff){
// Create variables for result
double sum = 0., mps = 0.;
int position = 0;
// Initialization of memo
....
// Finished initialization of memo
MpsTask1& root = *new(task::allocate_root()) MpsTask1(Cutoff,array,size,&sum,&mps,&position,memo);
task::spawn_root_and_wait(root);
}
我终于解决了。它确实来自我的代码。调用 spawn_and_wait_for_all()
时,它会调用先前生成的任务的 execute()
方法,但 gdb 似乎无法在回溯中显示该方法。对我有用的是将线程数设置为 1 并进行良好的旧 cout << endl << "Checkpoint" << endl
调试。
在本例中,我忘记了在 execute()
的第一个 if 中 return。代码的任何弱点似乎都会对 TBB 产生重大影响。
我正在尝试使用英特尔线程构建模块调试 C++ 代码,按照此处的过程 - Debugging in threading building Blocks。
我用一个线程尝试了 运行 代码,并将 TBB_USE_DEBUG 设置为 1(我在这里问了一个关于它的先前问题 -
#0 0x00007ffff793fbc1 in ?? () from /usr/lib/x86_64-linux-gnu/libtbb.so.2
#1 0x000000000040d2cb in tbb::task::spawn_and_wait_for_all (child=..., this=0x7ffff63b7a40)
at /usr/include/tbb/task.h:728
#2 MpsTask1::execute (this=0x7ffff63b7a40)
at /capps/mps_implementations.hpp:102
#3 0x00007ffff793ffdd in ?? () from /usr/lib/x86_64-linux-gnu/libtbb.so.2
#4 0x000000000040d2cb in tbb::task::spawn_and_wait_for_all (child=..., this=0x7ffff63b7d40)
at /usr/include/tbb/task.h:728
#5 MpsTask1::execute (this=0x7ffff63b7d40)
at /capps/mps_implementations.hpp:102
我对这个回溯感到很困惑,因为我无法控制库中发生的事情。有没有可能是我犯的错误导致 spawn_root_and_wait 失败?
这是我的代码(没有构造函数和析构函数以保持简短)。其目的是通过归约运算计算数组的最大前缀和。它递归地划分数组,直到块足够小,然后加入结果。我知道我可以使用 TBB parallel_reduce 模板来解决这个问题,但我的目标是了解基于 TBB 任务的编程是如何工作的。
class MpsTask1: public task {
public:
task* execute(){
if(size <= Cutoff){
for(int i = left; i != right; i++){
*sum = *sum + array[i]);
if (*sum <= *mps){
*mps = *sum;
*position = i+1;
}
}
memo[depth][index] = cutoff;
}else{
// Parameters for subtasks
int middle = (right+left)/2;
int sizel = middle - left;
int sizer = right - middle;
int newDepth = depth + 1;
int lIndex = 2*index;
int rIndex = lIndex + 1;
// Variables for results
int lPos = left;
int rPos = middle;
double lsum, rsum, lmps, rmps;
// Create subtasks
set_ref_count(3);
MpsTask1& lTask = *new(allocate_child()) MpsTask1(Cutoff,array,sizel,&lsum,&lmps,&lPos,memo,newDepth,lIndex,left,middle);
spawn(lTask);
MpsTask1 &rTask = *new(allocate_child()) MpsTask1(Cutoff,array,sizer,&rsum, &rmps,&rPos,memo,newDepth,rIndex,middle,right);
spawn_and_wait_for_all(rTask);
// Join results
rmps = lsum+rmps;
*sum = lsum+rsum;
if(*mps <= rmps){
*mps = rmps;
*position = rPos;
memo[depth][index] = rightChild;
}
else{
*mps_interval = lmps;
*position = lPos;
memo[depth][index] = leftChild;
}
return NULL;
}
}
private:
/* Below this size, the mps and sum are computed sequentially */
int Cutoff;
/* Input array and its size */
double* array;
int size;
/* Identification of the task */
int depth;
int index;
int left;
int right;
/* Intervals for sum and mps */
double* sum;
double* mps;
/* Position of the mps */
int* position;
// Status : left child, right child, or cutoff
Status** memo;
};
void parallel_mps(double* array, int size, int Cutoff){
// Create variables for result
double sum = 0., mps = 0.;
int position = 0;
// Initialization of memo
....
// Finished initialization of memo
MpsTask1& root = *new(task::allocate_root()) MpsTask1(Cutoff,array,size,&sum,&mps,&position,memo);
task::spawn_root_and_wait(root);
}
我终于解决了。它确实来自我的代码。调用 spawn_and_wait_for_all()
时,它会调用先前生成的任务的 execute()
方法,但 gdb 似乎无法在回溯中显示该方法。对我有用的是将线程数设置为 1 并进行良好的旧 cout << endl << "Checkpoint" << endl
调试。
在本例中,我忘记了在 execute()
的第一个 if 中 return。代码的任何弱点似乎都会对 TBB 产生重大影响。