我正在学习OpenMP并尝试并行化以下构造:
for (r = 0; r <= (int)(N/2); r++)
{
answer = ((answer % MOD) + (2 * (solve(N, r) % MOD)) % MOD) % MOD;
}
使用简化似乎很自然,但在这种情况下不支持模运算符。
此外,我尝试使用私有变量,但竞争条件仍然存在:
#pragma omp parallel for private(temp)
for (r = 0; r <= (int)(N/2); r++)
{
temp = answer;
answer = ((temp % MOD) + (2 * (solve(N, r) % MOD)) % MOD) % MOD;
}
有没有办法让它发挥作用? 感谢。
答案 0 :(得分:2)
您可以使用(x%a + y%a)%a = (x+y)%a的属性。然后
answer = ((answer % MOD) + (2 * (solve(N, r) % MOD)) % MOD) % MOD;
与
相同answer = (answer + 2 * solve(N, r) % MOD) % MOD;
总和,您可以显示这与
相同Sum(answer + 2 * solve(N, r) % MOD)%MOD
因此,您需要做的就是这个
#pragma omp parallel for reduction(+:answer)
for (r = 0; r <= (int)(N/2); r++)
{
answer += 2 * solve(N, r) % MOD
}
answer%=MOD;
这可能会溢出。在这种情况下,您可以像这样进行自定义缩减
#pragma omp parallel
{
int answer_private = 0;
#pragma omp for nowait
for(int i=0; i<n; i++) {
answer_private = ((answer_private % MOD) + (2 * (solve(N, r) % MOD)) % MOD) % MOD;
}
#pragma omp critical
{
answer = (answer%MOD + answer_private%MOD)%MOD;
}
}
答案 1 :(得分:0)
由于您受到OpenMP 2.0可能的限制,您的方法是编写自定义缩减。基本方案是:
omp_get_max_threads()
函数作为上限。用零(用于求和的标识元素)初始化它。omp_get_thread_num()
函数获取并行区域内当前线程的编号,并将其用作上述数组的索引。在相应的数组元素中累积结果。