OpenMP - 运行 带有 nowait 的单个区域,然后在 for 循环中加入其他线程

OpenMP - Run single region with nowait and after join other threads in for loop

我想做的是函数的第一部分 运行s 在单线程和其他线程中启动第二个函数(这个函数有三个循环)并且在单线程结束之后他与其他人一起加入的第一个功能是帮助处理循环。

我编写了以下代码,这是错误的,因为所有线程 运行 第二个函数,只需要一个到 运行 但都有助于循环。

void main(){


/* code */


#pragma omp parallel
{
     #pragma omp single nowait
     {
      std::cout << "Running func 1:" << omp_get_thread_num() << std::endl;
      func1();
      std::cout << "Finish func 1" <<std::endl;
     }

#pragma omp nowait

std::cout << "Running func 2:" << omp_get_thread_num() << std::endl;
func2();

#pragma omp barrier
}//close parallel


/* more code */

}//close main



void func2(void){

        /* code to read file */ 



#pragma omp parallel
{


     for (int i=40;i<60;i++){
          #pragma omp for nowait
          for (int j=0;j<100;j++){
           /* code  */
          }
      }

#pragma omp for schedule(dynamic,1) nowait
  for (int i=0;i<40;i++){
        for (int j=0;j<100;j++){
         /* code  */
       }
  }

#pragma omp for schedule(dynamic)
  for (int i=60;i<100;i++){
        for (int j=0;j<100;j++){
         /* code  */
        }
  }

         /* code to write file */ 

}//close parallel

#pragma omp barrier
} //close func2

我的终端显示:

Running func 1: 0
Running func 2: 1
Running func 2: 2
Running func 2: 3 
Finish func 1
Running func 2: 0 

编辑

观察:Func1 应该只在一个线程上执行

func2 已被拆分为三个 for 循环,因为第一个 for 比所有其他人加起来消耗更多的时间。如果我只使用一个 for 循环,所有其他线程将结束,一些将继续 运行。这样就先算出难的。

并行使用 Jim Cownie、func1 和 func2 运行 建议的代码,但是线程 运行 func2 两次或只有一个线程 运行 没有帮助其他人

即使有必要使用任务或部分,我有什么想法吗?

您的代码有很多问题

  1. 没有像 #pragma omp nowait 这样的 openMP 指令,因此您甚至可能没有在启用 OpenMP 的情况下进行编译(因为,当它启用时,您应该会收到一条错误消息;例如,请参阅 https://godbolt.org/z/EbYV6h )
  2. 在并行区域结束之前不需要 #pragma omp barrier(因为将执行下一个串行区域的主线程在所有线程也完成并行区域中的执行之前不能离开.)

我不明白你为什么要使用嵌套并行。您已经在并行执行 func2(),因此此处的任何嵌套都会导致超额订阅。

你也可以这样实现你想要的

#pragma omp parallel
{
#pragma omp single nowait
    func1()
  func2();
}

void func2()
{
#pragma omp for schedule(dynamic), nowait
    for (...)
        ... etc ...
}

或者,通过使用任务和任务循环,这可能是一种更简洁的表达方式。

使用任务,(而且,在你澄清你只想 function2 执行一次之后(我正在阅读代码所说的内容,因为这比读心术更容易!)),这样的事情有效

#include <unistd.h>
#include <stdio.h>
#include <omp.h>

void function1()
{
  fprintf(stderr,"%d: entering function1\n", omp_get_thread_num());
  sleep(1);
  fprintf(stderr,"%d: leaving function1\n", omp_get_thread_num());
}

void function2()
{
  fprintf(stderr,"%d: entering function2\n", omp_get_thread_num());
#pragma omp taskloop grainsize(1)                                                                                   
  for (int i=0; i<10; i++)
    {
      fprintf(stderr,"%d: starting iteration %d\n",
                     omp_get_thread_num(),i);
      sleep(1);
      fprintf(stderr,"%d: finishing iteration %d\n",
                     omp_get_thread_num(),i);
    }
  fprintf(stderr,"%d: leaving function2\n", omp_get_thread_num());
}

int main()
{
#pragma omp parallel
  {
#pragma omp single
    {
      fprintf(stderr,"Executing with %d threads\n",
                      omp_get_num_threads());
#pragma omp task
      {
        function1();
      }
#pragma omp task
      {
        function2();
      }
    }
  }
}

这里是四线程执行,当然其他交错也是可以的。

OMP_NUM_THREADS=4 ./a.out
Executing with 4 threads
3: entering function2
2: entering function1
0: starting iteration 0
1: starting iteration 1
3: starting iteration 9
1: finishing iteration 1
3: finishing iteration 9
0: finishing iteration 0
3: starting iteration 8
1: starting iteration 2
2: leaving function1
0: starting iteration 3
2: starting iteration 4
3: finishing iteration 8
1: finishing iteration 2
3: starting iteration 7
0: finishing iteration 3
0: starting iteration 6
2: finishing iteration 4
1: starting iteration 5
0: finishing iteration 6
3: finishing iteration 7
1: finishing iteration 5
3: leaving function2

您可以看到只有一个线程执行每个函数[12],并且所有线程共享循环迭代。