问题
When I run this code for n > 11 I get a debug error saying that abort() has been called. Using the visual studio debugger I found that it was on the task::spawn_root_and_wait(test); line of the code. I have no idea why it is doing this. When I ran the code using an array instead of a vector it ran fine but I was getting concurrency errors. Any advice?
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();
回答1:
The program is ill-formed for the following reasons which are not connected to TBB itself.
First, it generates accesses to the vector by negative index. It has
if (a < 0 && b < 0)
break;
but in case when only 'a' or only 'b' is negative, it proceeds to p[a] and p[b] accesses. It is the main reason why it fails.
Second, it assigns values to vector element concurrently, it will lead to inconsistent result at least. STL claims thread-safety for std::vector for read-only accesses only. tbb::concurrent_vector does not protects element accesses either. Please use mutex or atomic operations (e.g. compare_and_swap()
) to protect access to an element.
And the general advice, this low-level blocking-style of TBB programming is neither efficient (because the stack grows) nor readable. I'd recommend using high-level interfaces like tbb::parallel_invoke()
or tbb::task_group
来源:https://stackoverflow.com/questions/23338864/debug-error-when-calling-taskspawn-root-and-wait-in-tbb