调用tbb中的任务:spawn_root_and_wait时出现调试错误

Debug error when calling task::spawn_root_and_wait in tbb

本文关键字:wait 错误 调试 and root 任务 调用 spawn tbb      更新时间:2023-10-16

当我为n>11运行此代码时,我收到一个调试错误,说已经调用了abort()。使用visual studio调试器,我发现它正在执行以下任务::spawn_root_and_wait(测试);代码的行。我不知道它为什么要这么做。当我使用数组而不是向量运行代码时,它运行得很好,但我遇到了并发错误。有什么建议吗?

   vector<int> p;
class PartTask: public task
{
public:
    const int n;
    int* sum;

    PartTask(int n_, int* sum_) : n(n_), sum(sum_) {}
    task* execute()
    {
        int a, b;
        int alpha = 0, beta = 0;
        for (int k = 1; k < n; k++)
        {
            a = n - (k*(3 * k - 1) / 2);
            b = n - (k*(3 * k + 1) / 2);
            //cout << n << "t" << k << endl;
            //cout << a << "t" << b << endl;
            if (a < 0 && b < 0)
                break;

            if (a < 0)
                alpha = 0;
            else if (p[a] != -1)
                alpha = p[a];
            if (b < 0)
                beta = 0;
            else if (p[b] != -1)
                beta = p[b];

            if (p[a] == -1 && p[b] == -1)
            {
                int x = 0, y = 0;
                PartTask& taskA = *new(allocate_child()) PartTask(a, &x);
                PartTask& taskB = *new(allocate_child()) PartTask(b, &y);
                set_ref_count(3);
                spawn(taskA);
                spawn_and_wait_for_all(taskB);
                p[a] = x%5;
                p[b] = y%5;
                alpha = p[a];
                beta = p[b];
            }
            else if (p[a] == -1)
            {
                int x = 0;
                PartTask& taskA = *new(allocate_child()) PartTask(a, &x);
                set_ref_count(2);
                spawn_and_wait_for_all(taskA);
                p[a] = x%5;
                alpha = p[a];
            }
            else if (p[b] == -1)
            {
                int y = 0;
                PartTask& taskB = *new(allocate_child()) PartTask(b, &y);
                set_ref_count(2);
                spawn_and_wait_for_all(taskB);
                p[b] = y%5;
                beta = p[b];
            }
            //cout << "t" << alpha << "t" << beta << "t" << endl;
            if (k % 2 == 0)
                *sum += -1 * (alpha + beta);
            else
                *sum += alpha + beta;
            //cout << *sum << endl;
        }
        if (*sum > 0)
             *sum = *sum%5;
        else
            *sum = 5 + (*sum % 5);
        return NULL;
    }
};


   int main()
   {    
    int n;
    cin >> n;
    vector<int> temp(n,-1);
    p = temp;
    p.at(0) = 1 % 5;
    p.at(1) = 1 % 5;
    p.at(2) = 2 % 5;
    p.at(3) = 3 % 5;
    p.at(4) = 5 % 5;
    p.at(5) = 7 % 5;
    p.at(6) = 11 % 5;
    tick_count parallel_start = tick_count::now();
    task_scheduler_init init;
    int summ = 0;
    PartTask& test = *new(task::allocate_root()) PartTask(n, &summ);
    task::spawn_root_and_wait(test);
    tick_count parallel_end = tick_count::now();

由于以下原因,程序格式不正确,这些原因与TBB本身无关。

首先,它通过负索引生成对向量的访问。它有

  if (a < 0 && b < 0)
        break;

但在只有"a"或只有"b"为负的情况下,它进行p[a]和p[b]访问。这是它失败的主要原因。

其次,它同时为向量元素赋值,至少会导致结果不一致。STL声称std::vector的线程安全性仅用于只读访问。tbb::concurrent_vector也不保护元素访问。请使用互斥或原子操作(例如compare_and_swap())来保护对元素的访问。

一般的建议是,这种TBB编程的低级别阻塞样式既不高效(因为堆栈会增长),也不可读。我建议使用高级接口,如tbb::parallel_invoke()tbb::task_group