OMP parallel for 不划分迭代

OMP parallel for is not dividing iterations

我正在尝试使用 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。这意味着来自第一个并行区域的每个线程都会组成一个新团队。这称为嵌套并行性,它是允许的,但默认情况下它是关闭的。所以每个线程创建一个线程组,然后执行它的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("spin\n");
            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
    }
}