欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

openmp 快速入门 常用技巧 parallel for sections reduction critical

程序员文章站 2022-07-12 21:31:14
...

转载自:https://blog.csdn.net/billbliss/article/details/44131591

OpenMP并行执行的程序要全部结束后才能执行后面的非并行部分的代码。这就是标准的并行模式fork/join式并行模式,共享存储式并行程序就是使用fork/join式并行的。标准并行模式执行代码的基本思想是,程序开始时只有一个主线程,程序中的串行部分都由主线程执行,并行的部分是通过派生其他线程来执行,但是如果并行部分没有结束时是不会执行串行部分的。


摘要:

#pragma omp parallel
自动将下面语句执行N次,(N为电脑CPU核数),然后把每份指派给一个核去执行,而且多核之间为并行执行。
#pragma omp parallel for
并行执行相同代码段
自动将下面的for循环分成N份,(N为电脑CPU核数),然后把每份指派给一个核去执行,而且多核之间为并行执行。
#pragma omp parallel sections 和 #pragma omp parallel section
并行执行不同代码段,每个section都是一个线程,独立运行。
#pragma omp parallel for reduction(+:sum) 
归约
#pragma omp critical 
线程内互斥的代码段


#pragma omp parallel

自动将下面语句执行N次,(N为电脑CPU核数),然后把每份指派给一个核去执行,而且多核之间为并行执行。

  1. </pre><pre name="code" class="cpp">void parallel_test()
  2. {
  3. #pragma omp parallel
  4. {
  5. printf("hello from thread %d\n",omp_get_thread_num());
  6. }
  7. }

openmp 快速入门 常用技巧 parallel for sections reduction critical


#pragma omp parallel for

并行执行相同代码段

自动将下面的for循环分成N份,(N为电脑CPU核数),然后把每份指派给一个核去执行,而且多核之间为并行执行。


注意要点

1. for循环中的循环变量必须是有符号整形。例如,for (unsigned int i = 0; i < 10; ++i){}会编译不通过;

2. for循环中比较操作符必须是<, <=, >, >=。例如for (int i = 0; i != 10; ++i){}会编译不通过;

3. for循环中的第三个表达式,必须是整数的加减,并且加减的值必须是一个循环不变量。例如for (int i = 0; i != 10; i = i + 1){}会编译不通过;感觉只能++i; i++; --i; 或i--;

4. 如果for循环中的比较操作为<或<=,那么循环变量只能增加;反之亦然。例如for (int i = 0; i != 10; --i)会编译不通过;

5. 循环必须是单入口、单出口,也就是说循环内部不允许能够达到循环以外的跳转语句,exit除外。异常的处理也必须在循环体内处理。例如:若循环体内的break或goto会跳转到循环体外,那么会编译不通过。


  1. void parallel_for_test()
  2. {
  3. #pragma omp parallel for
  4. for (int i=0;i<10;i++)
  5. {
  6. printf("Loop: %d , thread NO: %d\n",i, omp_get_thread_num());
  7. }
  8. }

openmp 快速入门 常用技巧 parallel for sections reduction critical


#pragma omp parallel sections 和 #pragma omp parallel section

并行执行不同代码段,每个section都是一个线程,独立运行。

  1. void parallel_sections_test()
  2. {
  3. #pragma omp parallel sections
  4. {
  5. #pragma omp section
  6. {
  7. printf("section 1 thread NO: %d\n", omp_get_thread_num());
  8. }
  9. #pragma omp section
  10. {
  11. printf("section 2 thread NO: %d\n", omp_get_thread_num());
  12. }
  13. }
  14. }
openmp 快速入门 常用技巧 parallel for sections reduction critical


竞态条件(race condition):

这是所有多线程编程最棘手的问题。当多个线程并行执行时,有可能多个线程同时对某变量进行了读写操作,从而导致不可预知的结果。

比如,对于包含10个整型元素的数组a,我们用for循环求它各元素之和,并将结果保存在变量sum里。

openMP为我们提供了另一个工具,归约(reduction)

reduction很方便,但它支持一些基本操作,比如+,-,*,&,|,&&,||等。


#pragma omp parallel for reduction(+:sum)

  1. void reduction_test()
  2. {
  3. int sum = 0;
  4. int a[10] = {1,2,3,4,5,6,7,8,9,10};
  5. #pragma omp parallel for reduction(+:sum)
  6. for (int i=0;i<10;i++)
  7. {
  8. sum = sum + a[i];
  9. }
  10. printf("Sum: %d\n", sum);
  11. }
openmp 快速入门 常用技巧 parallel for sections reduction critical


有些情况下,我们既要避免race condition,但涉及到的操作又超出了reduction的能力范围。

这就要用到openMP的另一个工具,critical

执行到critical里面时,要注意有没有其他线程正在里面执行,如果有的话,要等其他线程执行完再进去执行。这样就避免了race condition问题,但显而易见,它的执行速度会变低,因为可能存在线程等待的情况。

比如,求数组a的最大值,将结果保存在max里。

#pragma omp critical

  1. void critical_test()
  2. {
  3. int max = 0;
  4. int a[10] = {11,2,33,49,113,20,321,250,689,16};
  5. #pragma omp parallel for
  6. for (int i=0;i<10;i++)
  7. {
  8. int temp = a[i];
  9. #pragma omp critical
  10. {
  11. if (temp > max)
  12. max = temp;
  13. }
  14. }
  15. printf("Max: %d\n", max);
  16. }

用#pragma omp critical将 if (temp > max) max = temp 括了起来,它的意思是:各个线程还是并行执行for里面的语句,但当你们执行到critical里面时,要注意有没有其他线程正在里面执行,如果有的话,要等其他线程执行完再进去执行。

openmp 快速入门 常用技巧 parallel for sections reduction critical


1. for循环中的循环变量必须是有符号整形。例如,for (unsigned int i = 0; i < 10; ++i){}会编译不通过;

2. for循环中比较操作符必须是<, <=, >, >=。例如for (int i = 0; i != 10; ++i){}会编译不通过;

3. for循环中的第三个表达式,必须是整数的加减,并且加减的值必须是一个循环不变量。例如for (int i = 0; i != 10; i = i + 1){}会编译不通过;感觉只能++i; i++; --i; 或i--;

4. 如果for循环中的比较操作为<或<=,那么循环变量只能增加;反之亦然。例如for (int i = 0; i != 10; --i)会编译不通过;

5. 循环必须是单入口、单出口,也就是说循环内部不允许能够达到循环以外的跳转语句,exit除外。异常的处理也必须在循环体内处理。例如:若循环体内的break或goto会跳转到循环体外,那么会编译不通过。


相关标签: opencl