线程构建块分段错误

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 产生重大影响。