OpenMP 参考(指令详解)

共享工作(Work-Sharing) 结构

  • 共享工作结构将它作用的代码段在抵达此代码段的线程中分开执行
  • Work-sharing 不会产生新线程
  • 进入工作共享结构时没有关卡,但结束时会有

Work-Sharing 结构的种类:

注意: 关于Fortran 的workshare 结构稍后讨论

DO / for - 在一组线程中共享循环中的计数器

(iteration). 表示一种 "数据并行处理".

SECTIONS - 将工作分成独立,不关联的片段。

每个片段被一个线程执行。用来实现一种

“函数并行处理”

SINGLE - 串行化代码段

 

 

 

规则:

  • 为了能并行执行此指令,一个工作共享结构必须被并行区域动态封闭
  • 一个线程组到达一个工作共享结构时,要么全部全线程被占用,要么不占用
  • 线程组的所有成员必须以相同的顺序到达连续的工作共享结构

 DO / for 指令

目的:

  • DO/for指令表明接下来的循环将被并行执行。前提是一个并行区域已经被初始化,否则以串行的方式执行。

 格式:

Fortran

 
!$OMP DO [clause ...] 
         SCHEDULE (type [,chunk]) 
         ORDERED 
         PRIVATE (list) 
         FIRSTPRIVATE (list) 
         LASTPRIVATE (list) 
         SHARED (list) 
         REDUCTION (operator | intrinsic : list) 
         COLLAPSE (n) 
 
   do_loop
 
!$OMP END DO  [ NOWAIT ]

C/C++

 
#pragma omp for [clause ...]  newline 
                schedule (type [,chunk]) 
                ordered
                private (list) 
                firstprivate (list) 
                lastprivate (list) 
                shared (list) 
                reduction (operator: list) 
                collapse (n) 
                nowait 
 
   for_loop

子句:

  • SCHEDULE: 描述线程组中的线程分配多少次循环。 默认schedule依赖于具体实现

STATIC

循环按照chunk的值被等分并静态赋予线程。如果没有指定chunk,那么将均分此循环。

DYNAMIC

循环按照chunk的值被等分并动态赋予线程。如果一个线程完成了一个分支,那么它将继续运行下一个分支。默认的chunk值为1.

GUIDED

如果chunk为1,每个分支的值为剩余的循环次数除以线程数量,减少到1.如果chunk的值为K(比1大),每块分支也以同样的方式分配迭代次数,只是每块的迭代次数不小于K。默认chunk的值为1.

RUNTIME

调度的策略依赖于运行时的环境变量OMP_SCHEDULE.为这个子句指定chunk的值是非法的。

AUTO

调度策略依赖于编译器或者运行时系统

  • NO WAIT / nowait: 如果指定了,线程在并行循环结束时不会同步.
  • ORDERED: 指定该循环迭代必须以串行方式执行.
  • COLLAPSE:指定在一个嵌套循环中,多少次循环被折叠到一个大的迭代空间并根据schedule子句来划分。所有相关循环中的迭代的执行顺序决定迭代空间中折叠迭代的顺序。
  • 其他的子句将在Data Scope Attribute Clauses 章节介绍

规则:

  • DO循环不能是DO WHILE循环,也不能没有循环控制。循环迭代变量必须是整型,并且对于所有的线程,循环控制参数都一样
  • 程序的正确性不能取决于那个线程执行了特定的迭代
  • 与DO/for 指令关联的循环要按照标准格式书写
  • 由于不同的线程在赋值时并不同步,chunk的值必须指定为一个循环的不变整型表达式
  • RDERED, COLLAPSE 和SCHEDULE 子句只可选其一.
  • 查看OpenMP的相关文档获得额外的信息

范例: DO / for 指令

  • 对vector执行加法操作的简单程序
    • 数组A, B, C, and 变量N 被所有线程共享.
    • 变量I对每个线程都是私有的;每个线程都会有一个它的唯一copy .
    • 循环的迭代将被动态地以CHUNK为单位分发.
    • 线程在完成各自的独立的工作时并不进行同步(NOWAIT).

Fortran - DO Directive Example

 
      PROGRAM VEC_ADD_DO 
      INTEGER N, CHUNKSIZE, CHUNK, I
      PARAMETER (N=1000) 
      PARAMETER (CHUNKSIZE=100) 
      REAL A(N), B(N), C(N) 
!     Some initializations
      DO I = 1, N
        A(I) = I * 1.0
        B(I) = A(I)
      ENDDO
      CHUNK = CHUNKSIZE
        
!$OMP PARALLEL SHARED(A,B,C,CHUNK) PRIVATE(I)
 
!$OMP DO SCHEDULE(DYNAMIC,CHUNK)
      DO I = 1, N
         C(I) = A(I) + B(I)
      ENDDO
!$OMP END DO NOWAIT
 
!$OMP END PARALLEL
 
      END

· 

C / C++ - for Directive Example

#include <omp.h>
#define CHUNKSIZE 100
#define N     1000 
main ()  
{ 
int i, chunk;
float a[N], b[N], c[N];
 
/* Some initializations */
for (i=0; i < N; i++)
  a[i] = b[i] = i * 1.0;
chunk = CHUNKSIZE; 
#pragma omp parallel shared(a,b,c,chunk) private(i)
  { 
  #pragma omp for schedule(dynamic,chunk) nowait
  for (i=0; i < N; i++)
    c[i] = a[i] + b[i]; 
  }  /* end of parallel section */
 
}

 

SECTIONS 指令

目的:

  • SECTIONS指令是一种非迭代式工作共享结构。它指定段中的代码被分配到线程组的线程中执行。
  • 独立的SECTION指令嵌套在SECTIONS指令中。每个SECTION仅被线程组中的一个线程执行。不同的段可能被不同的线程执行。在实现允许的情况下,如果一条线程足够快,它可能会执行好几个代码段。

 

格式:

Fortran

 
!$OMP SECTIONS [clause ...] 
               PRIVATE (list) 
               FIRSTPRIVATE (list) 
               LASTPRIVATE (list) 
               REDUCTION (operator | intrinsic : list) 
 
!$OMP  SECTION 
 
   block
 
!$OMP  SECTION 
 
    block 
 
!$OMP END SECTIONS  [ NOWAIT ]

C/C++

 
#pragma omp sections [clause ...]  newline 
                     private (list) 
                     firstprivate (list) 
                     lastprivate (list) 
                     reduction (operator: list) 
                     nowait
  {
 
  #pragma omp section   newline 
 
     structured_block
 
  #pragma omp section   newline 
 
     structured_block
 
  }

子句:

  • 如果NOWAIT/nowait子句没有被使用,在SECTIONS指令结束时会有一个隐藏的关卡(barrier)
  • 更多子句在Data Scope Attribute Clauses 章节详细讨论.

问答:

   

 

如果线程数量和SECTIONS的数量不一样会怎样?比SECTIONS多呢?比SECTIONS少呢?

 

 

 

 

哪条线程执行哪块SECTION?

规则:

  • section块要按照格式书写(It is illegal to branch into or out of section blocks.) 
  • SECTION指令只能出现在SECTIONS指令的静态范围内

范例: SECTIONS 指令

  • 展示不同的工作块被不同的线程执行的简单程序

Fortran - SECTIONS Directive Example

      PROGRAM VEC_ADD_SECTIONS 
      INTEGER N, I
      PARAMETER (N=1000)
      REAL A(N), B(N), C(N), D(N) 
!     Some initializations
      DO I = 1, N
        A(I) = I * 1.5
        B(I) = I + 22.35
      ENDDO 
!$OMP PARALLEL SHARED(A,B,C,D), PRIVATE(I) 
!$OMP SECTIONS 
!$OMP SECTION
      DO I = 1, N
         C(I) = A(I) + B(I)
      ENDDO
!$OMP SECTION
      DO I = 1, N
         D(I) = A(I) * B(I)
      ENDDO 
!$OMP END SECTIONS NOWAIT 
!$OMP END PARALLEL
 
      END

· 

C / C++ - sections Directive Example

 
#include <omp.h>
#define N     1000 
main ()
{ 
int i;
float a[N], b[N], c[N], d[N]; 
/* Some initializations */
for (i=0; i < N; i++) {
  a[i] = i * 1.5;
  b[i] = i + 22.35;
  } 
#pragma omp parallel shared(a,b,c,d) private(i)
  { 
  #pragma omp sections nowait
    { 
    #pragma omp section
    for (i=0; i < N; i++)
      c[i] = a[i] + b[i]; 
    #pragma omp section
    for (i=0; i < N; i++)
      d[i] = a[i] * b[i];
 
    }  /* end of sections */ 
  }  /* end of parallel section */
 
}

 

WORKSHARE 指令

目的:

  • Fortran 适用
  • WORKSHARE指令将密封的结构块分成一些独立的工作单元来执行,每个工作单元被执行一次。
  • 结构块只能由如下组成:
    • array assignments
    • scalar assignments
    • FORALL statements
    • FORALL constructs
    • WHERE statements
    • WHERE constructs
    • atomic constructs
    • critical constructs
    • parallel constructs
  • 更多信息请查看OpenMP API 文档.

格式:

Fortran

 
!$OMP WORKSHARE
 
   structured block
 
!$OMP END WORKSHARE [ NOWAIT ]

规则:

  • 除了ELEMENTAL函数,该结构不能包含任何用户函数调用.

范例: WORKSHARE 指令

  • Simple array and scalar assigments shared by the team of threads. A unit of work would include:
    • Any scalar assignment
    • For array assignment statements, the assignment of each element is a unit of work

Fortran - WORKSHARE Directive Example

 
      PROGRAM WORKSHARE
 
      INTEGER N, I, J
      PARAMETER (N=100)
      REAL AA(N,N), BB(N,N), CC(N,N), DD(N,N), FIRST, LAST
 
!     Some initializations
      DO I = 1, N
        DO J = 1, N
          AA(J,I) = I * 1.0
          BB(J,I) = J + 1.0
        ENDDO
      ENDDO
 
!$OMP PARALLEL SHARED(AA,BB,CC,DD,FIRST,LAST)
 
!$OMP WORKSHARE
      CC = AA * BB
      DD = AA + BB
      FIRST = CC(1,1) + DD(1,1)
      LAST = CC(N,N) + DD(N,N)
!$OMP END WORKSHARE NOWAIT
 
!$OMP END PARALLEL
 
      END

 

SINGLE Directive

目的:

  • SINGLE 指令表示其作用的代码将单线程执行.
  • 当执行非线程安全代码段(如I/O)时会派上用场

格式:

Fortran

 
!$OMP SINGLE [clause ...] 
             PRIVATE (list) 
             FIRSTPRIVATE (list) 
 
   block
 
!$OMP END SINGLE [ NOWAIT ]

C/C++

 
#pragma omp single [clause ...]  newline 
                   private (list) 
                   firstprivate (list) 
                   nowait
 
     structured_block

子句:

  • 除非指定了NOWAIT/nowait指令,线程组中没有执行SINGLE指令的线程将在密封代码块的结束处等待.
  • 更多的子句描述见Data Scope Attribute Clauses 章节.

规则:

  • SINGLE块要按照格式书写(It is illegal to branch into or out of a SINGLE block. )

 

合并的并行工作共享结构

OpenMP提供了三个方便指令:

    • PARALLEL DO / parallel for
    • PARALLEL SECTIONS
    • PARALLEL WORKSHARE (fortran 适用)
  • 大多数情况下,这些指令的行为和一个独立的PARALLEL指令后面紧跟一个单独的work-sharing指令相同
  • 大多数对指令的法则,子句和限制都有效。更多细节参考OpenMP API.
  • 下面是一个使用PARALLEL DO/PARALLEL FOR联合指令的范例 .

Fortran - PARALLEL DO Directive Example

 
      PROGRAM VECTOR_ADD
 
      INTEGER N, I, CHUNKSIZE, CHUNK
      PARAMETER (N=1000) 
      PARAMETER (CHUNKSIZE=100) 
      REAL A(N), B(N), C(N)
 
!     Some initializations
      DO I = 1, N
        A(I) = I * 1.0
        B(I) = A(I)
      ENDDO
      CHUNK = CHUNKSIZE
             
!$OMP PARALLEL DO
!$OMP& SHARED(A,B,C,CHUNK) PRIVATE(I) 
!$OMP& SCHEDULE(STATIC,CHUNK)
 
      DO I = 1, N
         C(I) = A(I) + B(I)
      ENDDO
 
!$OMP END PARALLEL DO
 
      END

· 

C / C++ - parallel for Directive Example

 
#include <omp.h>
#define N       1000
#define CHUNKSIZE   100
 
main ()  {
 
int i, chunk;
float a[N], b[N], c[N];
 
/* Some initializations */
for (i=0; i < N; i++)
  a[i] = b[i] = i * 1.0;
chunk = CHUNKSIZE;
 
#pragma omp parallel for /
   shared(a,b,c,chunk) private(i) /
   schedule(static,chunk)
  for (i=0; i < n; i++)
    c[i] = a[i] + b[i];
}

 

 

TASK 构造

目的:

  • OpenMP 3.0的新构造
  • TASK构造定义一个显式任务,该任务被遇到的线程执行,或者被线程组中的其他线程推迟执行
  • 数据共享属性子句决定它的数据环境
  • Task的执行遵从任务调度-更多信息请查看OpenMP3.0参考文档

Format:

Fortran

 
!$OMP TASK [clause ...] 
             IF (scalar expression) 
             UNTIED
             DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE)
             PRIVATE (list) 
             FIRSTPRIVATE (list) 
             SHARED (list) 
 
   block
 
!$OMP END TASK

C/C++

 
#pragma omp task [clause ...]  newline 
                   if (scalar expression) 
                   untied
                   default (shared | none)
                   private (list) 
                   firstprivate (list) 
                   shared (list) 
 
     structured_block

子句和限制:

  • 请参考 OpenMP 3.0 规范文档

 

 

你可能感兴趣的:(工作,list,Integer,fortran,parallel,newline)