我有以下代码:
#pragma omp parallel for private(dist,i,j)
for(k=0;k<K;k++)
{
//some code
for(i=0;i<N;i++)
{
#pragma omp critical
{
if(min_dist[i]>dist[i])//The point i belongs to the cluster k
{
newmembership[i]=k;
min_dist[i]=dist[i];
}
}
dist[i]=0;
}
}
dist是一个私有变量,而newmemebership和min_dist是一个共享变量。对于我的测试用例,如果我们运行代码而不添加关键部分构造,代码仍然有效。据我所知,它不应该作为两个线程可能正在运行i的相同值,并可能修改导致冲突的min_dist [i]和newmembership [i]。
请解释是否有必要添加关键部分构造,还有更好的方法来实现上述即使用锁或信号量吗?
答案 0 :(得分:3)
删除critical
部分将是一场数据竞赛。请考虑以下执行:
(min_dist[42] == 100)
time | Thread 0 | Thread 1
----------------------------------------------------------------------
0 | k = 13 |
1 | i = 42 | k = 14
2 | dist[i] = 50 | i = 42
3 | min_dist[i] > dist[i] ==> true | dist[i] = 75
4 | newmembership[i] = 13 | min_dist[i] > dist[i] ==> true
5 | min_dist[i]=50 | newmembership[i] = 14
6 | ... | min_dist[i]=75
所以你最终得到了一个非最小的解决方案。您最终可能会遇到有冲突的min_dist
/ newmembership
值。
另一种方法是创建线程private
local_min_dist
/ local_newmembership
数组,并在执行结束时合并它们:
#pragma omp parallel
{
// Note: implicitly private because defined inside the parallel region
int local_newmembership[N];
int local_min_dist[N];
#pragma omp for private(dist,i,j)
for(k=0;k<K;k++)
{
//some code
for(i=0;i<N;i++)
{
// NOTE: No critical region necessary
// as we operate on private variables
if(local_min_dist[i]>dist[i])//The point i belongs to the cluster k
{
local_newmembership[i]=k;
local_min_dist[i]=dist[i];
}
dist[i]=0;
}
}
for (i = 0; i < N; i++)
{
// Here we have a critical region,
// but it is outside of the k-loop
#pragma omp critical
if (min_dist[i] > local_min_dist[i])
{
newmembership[i] = local_newmembership[i];
local_min_dist[i] = local_min_dist[i];
}
}
}