OMP并行for不是划分迭代



我正在尝试使用omp.h进行分布式搜索。我正在创建4个线程。id为0的线程不执行搜索,而是查询哪个线程在数组中找到了该数字。下面是我的代码:

int arr[15]; //This array is randomly populated
int process=0,i=0,size=15; bool found=false;

#pragma omp parallel num_threads(4)
{
int thread_id = omp_get_thread_num();
#pragma omp cancellation point parallel

if(thread_id==0){
while(found==false){ continue; }
if(found==true){
cout<<"Number found by thread: "<<process<<endl;
#pragma omp cancel parallel
}

}
else{
#pragma omp parallel for schedule(static,5)

for(i=0;i<size;i++){

if(arr[i]==number){  //number is a int variable and its value is taken      from user
found = true;
process = thread_id;


}
cout<<i<<endl;
}
}

}

我的问题是,每个线程执行循环从i=0直到i=14。根据我的理解,omp划分了循环的迭代,但这里没有。谁能告诉我原因和可能的解决方案?

您的问题是您在parallel中有parallel。这意味着来自第一个并行区域的每个线程组成一个新团队。这被称为嵌套并行,它是允许的,但默认情况下它是关闭的。因此,每个线程创建一个由1个线程组成的团队,然后执行它的for循环部分,也就是整个循环。

所以你的omp parallel for应该是omp for

但是现在有另一个问题:你的循环将分布在所有线程上,除了线程0永远不会到达循环。这样就会出现死锁

…这个问题的实际解要复杂得多。它涉及创建两个任务,一个在共享变量上旋转,另一个进行并行搜索。

#pragma omp parallel
{
#   pragma omp single
{
int p = omp_get_num_threads();
int found = 0;
#     pragma omp taskgroup
{
/*
* Task 1 listens to the shared variable
*/
#       pragma omp task shared(found)
{
while (!found) {
if (omp_get_thread_num()<0) printf("spinn");
continue; }
printf("found!n");
#         pragma omp cancel taskgroup
} // end 1st task
/*
* Task 2 does something in parallel,
* sets `found' to true if found
*/
#     pragma omp task shared(found)
{
#         pragma omp parallel num_threads(p-1)
#         pragma omp for
for (int i=0; i<p; i++)
// silly test
if (omp_get_thread_num()==2) {
printf("two!n");
found = 1;
}
} // end 2nd task
} // end taskgroup
}
}

(你注意到从未执行过的printf了吗?我需要它来防止编译器"优化掉"。空while循环)

奖励解决方案:

#pragma omp parallel num_threads(4)
{
if(omp_get_thread_num()==0){  spin_on_found; }
if(omp_get_thread_num()!=0){
#pragma omp for nowait schedule(dynamic)  
for ( loop ) stuff

dynamicnowait的组合可以以某种方式处理缺失的线程。

  1. @Victor Eijkhout已经解释了这里发生的事情,我只是想向您展示一个更简单(并且没有数据竞争)的解决方案。

  2. 请注意,OpenMP有一个显著的开销,在您的情况下,开销大于并行化的增益。因此,在这种情况下,最好不要使用并行化。

  3. 如果在循环中执行了一些开销较大的工作,最简单的解决方案是在不必要的情况下跳过这些开销较大的工作。注意,为了避免数据竞争,我在found = true;之前使用了#pragma omp critical

#pragma omp parallel for
for(int i=0; i<size;i++){
if(found) continue;
// some expensive work here
if(CONDITION){  
#pragma omp critical
found = true;        
}
}
  1. 另一种选择是使用#pragma omp cancel for
#pragma omp parallel 
#pragma omp for 
for(int i=0; i<size;i++){
#pragma omp cancellation point for
// some expensive work here
if(CONDITION){       
//cancelling the for loop
#pragma omp cancel for
}
}

最新更新