Chapter 5. OpenMP Multiprocessing Directives

This chapter describes the multiprocessing directives suported by the MIPSpro Fortran 77 compiler. These directives are based on the OpenMP Fortran API standard. Programs that use these directives are portable and can be compiled by other compilers that support the OpenMP standard.

Directives enable, disable, or modify a feature of the compiler. Essentially, directives are command line options specified within the input file instead of on the command line. Unlike command line options, directives have no default setting. To invoke a directive, you must either toggle it on or set a desired value for its level.

In addition to directives, the OpenMP Fortran API describes several library routines and environment variables. Information on the library routines can be found on the omp_lock(3), omp_nested(3), and omp_threads(3) man pages. Information about the environment variables can be found on the pe_environ(5) man page.

This chapter discusses the following directives:

In addition, clauses to control scope attributes are discusssed in “Defining Parallel Regions”.

A data environment is associated with each process; this environment provides a context for execution. A data environment is initiated at the start of a program. New environments are constructed for new processes created during program execution. The objects comprising a data environment can have a SHARED, PRIVATE, or REDUCTION attribute. All of these attributes are discussed later in this chapter.

Using Directives

OpenMP directives are ignored by default. To enable both the newer OpenMP directives and the older multiprocessing directives, use the f77 -mp command. To disable either type of directive, use one of the following commands:.

f77 -mp -MP:open_mp=off
f77 -mp -MP:old_mp=off

Directives placed on the first line of the input file are called global directives. The compiler interprets them as if they appeared at the top of each program unit in the file. Directives that appear elsewhere in the file apply only until the end of the current program unit. The compiler resets the value of the directive to the global value at the start of the next program unit. You can set the global value using a command line option or a global directive.

Some command line options override directives and many directives have corresponding command line options. If you specify conflicting settings in the command line and in a directive, the compiler chooses the most restrictive setting. For Boolean options, if either the directive or the command line has the option turned off, it is considered off. For options that require a numeric value, the compiler uses the minimum of the command line setting and the directive setting.

The compiler directives look like Fortran comments: they begin with a C in column one. If multiprocessing is not turned on, the statements are treated as comments. This allows the identical source to be compiled with a single-processing compiler or by the compiler without the multiprocessing option.

All multiprocessing directives are case-insensitive and are of the following form:

prefix directive [clause[[,] clause]...]

The C$OMP and *$OMP prefixes can be used.

Prefixes must start in column one and appear as a single word with no intervening white space. Fortran fixed form line length, case sensitivity, white space, continuation, and column rules apply to the directive line.

The clause indicates one or more directive clauses. Clauses can appear in any order after the directive name and can be repeated as needed, subject to the restrictions listed in the description of each clause.

Directives cannot be embedded within continued statements, and statements cannot be embedded within directives. Comments cannot appear on the same line as a directive.

The following formats for specifying directives are equivalent (the first line represents the position of the first 9 columns):

C23456789

C$OMP PARALLEL DO

C$OMP+SHARED(A,B,C)

C$OMP PARALLELDOSHARED(A,B,C)

In order to simplify the presentation, the remainder of this chapter uses the C$OMP prefix in all syntax descriptions and examples.

Initial directive lines must have a space or zero in column six, and continuation directive lines must have a character other than a space or a zero in column six.

Conditional Compilation

Conditional compilation can be used to comment out sections of code. When using conditional compilation, the code is commented out if the -mp compile option is not used.

Fortran statements can be compiled conditionally as long as they are preceded by one of the following conditional compilation prefixes:, C$, or *$. The prefix must be followed by a legal Fortran statement on the same line. During compilation, the prefix is replaced by two spaces, and the rest of the line is treated as a normal Fortran statement.

The prefixes must start in column one and appear as a single word with no intervening white space. Fortran fixed form line length, case sensitivity, white space, continuation, and column rules apply to the line. Initial lines must have a space or zero in column six, and continuation lines must have a character other than a space or zero in column six.

Example. The following forms for specifying conditional compilation are equivalent:

C23456789
C$ 10 IAM = OMP_GET_THREAD_NUM() +
C$   &          INDEX

#ifdef _OPENMP
     10 IAM = OMP_GET_THREAD_NUM() +
       &          INDEX
#endif

In addition to the Fortran conditional compilation prefixes, a preprocessor macro, _OPENMP, can be used for conditional compilation.

Defining Parallel Regions

The PARALLEL and ENDPARALLEL directives define a parallel region. A parallel region is a block of code that is to be executed by multiple threads in parallel. This is the fundamental OpenMP parallel construct that starts parallel execution. These directives have the following format:

C$OMP PARALLEL [clause [[,] clause]...]
block
C$OMP END PARALLEL

The clause can be one or more of the following:

  • PRIVATE(var[, var] ...)

  • SHARED(var[, var ]...)

  • DEFAULT(PRIVATE | SHARED | NONE)

  • FIRSTPRIVATE(var,[ var] ...)

  • REDUCTION ({operator|intrinsic}:var[, var]...)

  • IF(scalar_logical_expression)

  • COPYIN(var[, var] ...)

The PRIVATE, SHARED, DEFAULT, FIRSTPRIVATE, REDUCTION, and COPYIN clauses are described in “Defining Parallel Regions”.

The block denotes a structured block of Fortran statements. You cannot branch into or out of the block. The code contained within the dynamic extent of the parallel region is executed on each thread, and the code path can be different for different threads.

The ENDPARALLEL directive denotes the end of the parallel region. There is an implied barrier at this point. Only the master thread of the team continues execution at the end of a parallel region.

When a thread encounters a parallel region, it creates a team of threads, and it becomes the master of the team. The master thread is a member of the team and it has a thread number of 0 within the team. The number of threads in the team is controlled by environment variables and/or library calls.

The number of physical processors actually hosting the threads at any given time is implementation dependent. Once created, the number of threads in the team remains constant for the duration of that parallel region, but it can be changed either explicitly by the user or automatically by the run-time system from one parallel region to another. The OMP_SET_DYNAMIC library routine and the OMP_DYNAMIC environment variable can be used to enable and disable the automatic adjustment of the number of threads. For more information about environment variables that affect OpenMP directives, see the pe_environ(5) man page.


Note: The OpenMP Fortran API does not specify the number of physical processors that can host the threads at any given time.

If a thread in a team executing a parallel region encounters another parallel region, it creates a new team, and it becomes the master of that new team. By default, nested parallel regions are serialized; that is, they are executed by a team composed of one thread. This default behavior can be changed by using either the OMP_SET_NESTED library routine or the OMP_NESTED environment variable. For more information on environment variables that affect OpenMP directives, see the pe_environ(5) man page.

If an IF clause is present, the enclosed code region is executed in parallel only if the scalar_logical_expression evaluates to .TRUE.. Otherwise, the parallel region is serialized. The expression must be a scalar Fortran logical expression.

The following restrictions apply to parallel regions:

  • The PARALLEL/ENDPARALLEL directive pair must appear in the same routine in the executable section of the code.

  • The code contained by these two directives must be a structured block. You cannot branch into or out of a parallel region.

  • Only a single IF clause can appear on the directive.

Work-sharing Constructs

A work-sharing construct divides the execution of the enclosed code region among the members of the team that encounter it. A work-sharing construct must be enclosed within a parallel region in order for the directive to execute in parallel. The work-sharing directives do not launch new threads, and there is no implied barrier on entry to a work-sharing construct.

The following restrictions apply to the work-sharing directives:

  • Work-sharing constructs and BARRIER directives must be encountered by all threads in a team or by none at all.

  • Work-sharing constructs and BARRIER directives must be encountered in the same order by all threads in a team.

The following sections describe the work-sharing constructs.

DO Directive

The DO directive specifies that the iterations of the immediately following DO loop will be divided among the parallel threads. The loop that follows a DO directive cannot be a DOWHILE or a DO loop without loop control. The iterations of the DO loop are distributed across threads that already exist.

The format of this directive is as follows:

C$OMP DO [clause[[, ]clause]...]
do_loop
[C$OMP END DO [NOWAIT]]

The clause can be one of the following:

  • PRIVATE(var[, var] ...)

  • FIRSTPRIVATE(var[, var] ...)

  • LASTPRIVATE(var[, var] ...)

  • REDUCTION({operator|intrinsic}:var[, var]...)

  • SCHEDULE(type[,chunk])

  • ORDERED

See “Defining Parallel Regions”, for information about these clauses.

If ordered sections are contained in the dynamic extent of the DO directive, the ORDERED clause must be present. The code enclosed within an ordered section is executed in the order in which iterations would be executed in a sequential execution of the loop.

The SCHEDULE clause specifies how iterations of the DO loop are divided among the threads of the team. Within the SCHEDULE(type,chunk) clause syntax, type can be one of the following:

type

Effect

STATIC

When SCHEDULE(STATIC, chunk) is specified, iterations are divided into pieces of a size specified by chunk. The pieces are statically assigned to threads in the team in a round-robin fashion in the order of the thread number. chunk must be a scalar integer expression.

When no chunk is specified, the iterations are divided among threads in contiguous pieces, and one piece is assigned to each thread.

DYNAMIC

When SCHEDULE(DYNAMIC,chunk) is specified, the iterations are broken into pieces of a size specified by chunk. As each thread finishes its iterations, it dynamically obtains the next set of iterations. When no chunk is specified, it defaults to 1.

GUIDED

When SCHEDULE(GUIDED,chunk) is specified, the chunk size is reduced in an exponentially decreasing manner with each dispatched piece of the iteration space. chunk specifies the minimum number of iterations to dispatch each time, except when there are less than chunk number of iterations, at which point the rest are dispatched. When no chunk is specified, the default is 1.

RUNTIME

When SCHEDULE(RUNTIME) is specified, the decision regarding scheduling is deferred until run time and you cannot specify a chunk.

The schedule type and chunk size can be chosen at run time by setting the OMP_SCHEDULE environment variable. If not set, the default is STATIC.

For more information about the OMP_SCHEDULE environment variable, see the pe_environ(5) man page.


Note: The OpenMP Fortran API does not define a default scheduling mechanism. You should not rely on a particular implementation of a schedule type for correct execution because it is possible to have variations in the implementations of the same schedule type across different compilers.

If an ENDDO directive is not specified, it is assumed at the end of the DO loop. If NOWAIT is specified on the ENDDO directive, threads do not synchronize at the end of the parallel loop. Threads that finish early proceed straight to the instructions following the loop without waiting for the other members of the team to finish the DO directive.

Parallel DO loop control variables are block-level entities within the DO loop. If the loop control variable also appears in the LASTPRIVATE variable list of the parallel DO, it is copied out to a variable of the same name in the enclosing PARALLEL region. The variable in the enclosing PARALLEL region must be SHARED if it is specified on the LASTPRIVATE variable list of a DO directive.

The following restrictions apply to the DO directives:

  • You cannot branch out of a DO loop associated with a DO directive.

  • The values of the loop control parameters of the DO loop associated with a DO directive must be the same for all the threads in the team.

  • The DO loop iteration variable must be of type integer.

  • If used, the ENDDO directive must appear immediately after the end of the loop.

  • Only a single SCHEDULE clause can appear on a DO directive.

  • Only a single ORDERED clause can appear on a DO directive.

SECTIONS Directive

The SECTIONS directive specifies that the enclosed sections of code are to be divided among threads in the team. It is a non-iterative work-sharing construct. Each section is executed once by a thread in the team.

The format of this directive is as follows:

C$OMP SECTIONS [clause[[,] clause]...]
C$OMP SECTION
block
[C$OMP SECTION
block]
. . .
C$OMP END SECTIONS [NOWAIT]

The clause can be one of the following:

  • PRIVATE(var[, var ]...)

  • FIRSTPRIVATE(var[, var] ...)

  • LASTPRIVATE(var[, var] ...)

  • REDUCTION({ operator|intrinsic}:var[, var]...)

The PRIVATE, FIRSTPRIVATE, LASTPRIVATE, and REDUCTION clauses are described in “Defining Parallel Regions”.

The block denotes a structured block of Fortran statements. You cannot branch into or out of the block.

Each section must be preceded by a SECTION directive, though the SECTION directive is optional for the first section. The SECTION directives must appear within the lexical extent of the SECTIONS/ENDSECTIONS directive pair. The last section ends at the ENDSECTIONS directive. Threads that complete execution of their sections wait at a barrier at the ENDSECTIONS directive unless a NOWAIT is specified.

The following restrictions apply to the SECTIONS directive:

  • The code enclosed in a SECTIONS/ENDSECTIONS directive pair must be a structured block. In addition, each constituent section must also be a structured block. You cannot branch into or out of the constituent section blocks.

  • You cannot have a SECTION directive outside the lexical extent of the SECTIONS/ENDSECTIONS directive pair.

SINGLE Directive

The SINGLE directive specifies that the enclosed code is to be executed by only one thread in the team. Threads in the team that are not executing the SINGLE directive wait at the ENDSINGLE directive unless NOWAIT is specified.

The format of this directive is as follows:

C$OMP SINGLE [clause[,] clause]...]
block
C$OMP END SINGLE [NOWAIT]

The clause can be one of the following:

  • PRIVATE(var[, var] ...)

  • FIRSTPRIVATE(var[, var] ...)

The PRIVATE and FIRSTPRIVATE clauses are described in “Defining Parallel Regions”.

The block denotes a structured block of Fortran statements. You cannot branch into or out of the block.

Combined Parallel Work-sharing Constructs

The combined parallel work-sharing constructs are shortcuts for specifying a parallel region that contains only one work-sharing construct. The semantics of these directives are identical to that of explicitly specifying a PARALLEL directive followed by a single work-sharing construct.

The following sections describe the combined parallel work-sharing directives.

PARALLEL DO Directive

The PARALLEL DO directive provides a shortcut form for specifying a parallel region that contains a single DO directive.

The format of this directive is as follows:

C$OMP PARALLEL DO [clause[[,] clause...]
do_loop
[C$OMP END PARALLEL DO]

The clause can be one or more of the clauses accepted by the PARALLEL directive or the DO directive, as follows:

  • PRIVATE(var[, var] ...)

  • FIRSTPRIVATE(var[, var] ...)

  • LASTPRIVATE(var[, var] ...)

  • REDUCTION({operator|intrinsic}:var[, var] ...)

  • SCHEDULE(type[,chunk])

  • ORDERED

  • SHARED(var[, var] ...)

  • DEFAULT(PRIVATE | SHARED | NONE)

  • IF(scalar_logical_expression)

  • COPYIN(var[, var] ...)

See “Defining Parallel Regions”, for details about these clauses.

If the END PARALLEL DO directive is not specified, the PARALLEL DO is assumed to end with the DO loop that immediately follows the PARALLEL DO directive. If used, the END PARALLEL DO directive must appear immediately after the end of the DO loop.

The semantics are identical to explicitly specifying a PARALLEL directive immediately followed by a DO directive.

PARALLEL SECTIONS Directive

The PARALLEL SECTIONS directive provides a shortcut form for specifying a parallel region that contains a single SECTIONS directive. The semantics are identical to explicitly specifying a PARALLEL directive immediately followed by a SECTIONS directive.

The format of this directive is as follows:

C$OMP PARALLEL SECTIONS [clause[[,] clause]...]
[C$OMP SECTION]
block
[C$OMP SECTION
block]
. . .
C$OMP END PARALLEL SECTIONS

The clause can be one or more of the clauses accepted by the PARALLEL directive or the SECTIONS directive. These clauses are as follows:

  • PRIVATE(var[, var] ...)

  • FIRSTPRIVATE(var[, var] ...)

  • LASTPRIVATE(var[, var] ...)

  • REDUCTION({ operator|intrinsic}:var[,var]...)

  • SHARED(var[, var] ...)

  • DEFAULT(PRIVATE | SHARED | NONE)

  • IF(scalar_logical_expression)

  • COPYIN(var[, var] ...)

See “Defining Parallel Regions”, for details about these clauses.

The block denotes a structured block of Fortran statements. You cannot branch into or out of the block.

The last section ends at the END PARALLEL SECTIONS directive.

Synchronization Constructs

The following synchronization constructs are discussed in this section:

MASTER Directive

The code enclosed within MASTER and ENDMASTER directives is executed by the master thread.

These directives have the following format:

C$OMP MASTER
block
C$OMP END MASTER

The block denotes a structured block of Fortran statements. You cannot branch into or out of the block. The other threads in the team skip the enclosed section of code and continue execution. There is no implied barrier either on entry to the master section or exit from the master section.

CRITICAL Directive

The CRITICAL and END CRITICAL directives restrict access to the enclosed code to one thread at a time.

These directives have the following format:

C$OMP CRITICAL [(name)]
block
C$OMP END CRITICAL [(name)]

The name identifies the critical section. If a name is specified on a CRITICAL directive, the same name must also be specified on the END CRITICAL directive. If no name appears on the CRITICAL directive, no name can appear on the END CRITICAL directive.

The block denotes a structured block of Fortran statements. You cannot branch into or out of the block.

A thread waits at the beginning of a critical section until no other thread in the team is executing a critical section with the same name. All unnamed CRITICAL directives map to the same name. Critical section names are global entities of the program. If a name conflicts with any other entity, the behavior of the program is undefined.

BARRIER Directive

The BARRIER directive synchronizes all the threads in a team. When it encounters a barrier, a thread waits until all other threads have reached the same point.

This directive has the following format:

C$OMP BARRIER

ATOMIC Directive

The ATOMIC directive ensures that a specific memory location is updated atomically, rather than exposing it to the possibility of multiple, simultaneous writing threads.

This directive has the following format:

C$OMP ATOMIC

This directive applies only to the immediately following statement, which must have one of the following forms:

  • x = x operator expr

  • x = expr operator x

  • x = intrinsic (x, expr)

  • x = intrinsic (expr, x)

In the preceding statements:

  • x is a scalar variable of intrinsic type. All references to storage location x must have the same type and type parameters.

  • expr is a scalar expression that does not reference x.

  • intrinsic is one of MAX, MIN, IAND, IOR, or IEOR.

  • operator is one of +, *, -, /, .AND., .OR., .EQV., or .NEQV. .

Only the load and store of x are atomic; the evaluation of expr is not atomic. To avoid race conditions, all updates of the location in parallel must be protected with the ATOMIC directive, except those that are known to be free of race conditions. The following is an example:

C$OMP ATOMIC
      Y(INDEX(I)) = Y(INDEX(I)) + B

FLUSH Directive

The FLUSH directive identifies synchronization points at which thread-visible variables are written back to memory. This directive must appear at the precise point in the code at which the synchronization is required.

Thread-visible variables include the following data items:

  • Globally visible variables (common blocks).

  • Local variables that do not have the SAVE attribute but have had their address taken and saved or have had their address passed to another subprogram.

  • Local variables that do not have the SAVE attribute that are declared shared in a parallel region within the subprogram.

  • Dummy arguments.

  • All pointer dereferences.

This directive has the following format:

C$OMP FLUSH [(var[, var] ...)]

The var argument indicates the variables to be flushed.

An implicit FLUSH directive is assumed for the following directives:

  • BARRIER

  • CRITICAL and END CRITICAL

  • END DO

  • END PARALLEL

  • END SECTIONS

  • END SINGLE

  • ORDERED and END ORDERED

The directive is not implied if a NOWAIT clause is present.

ORDERED Directive

The code enclosed within ORDERED and END ORDERED directives is executed in the order in which iterations would be executed in a sequential execution of the loop.

These directives have the following format:

C$OMP ORDERED
block
C$OMP END ORDERED

The block denotes a structured block of Fortran statements. You cannot branch into or out of the block.

An ORDERED directive can appear only in the dynamic extent of a DO or PARALLEL DO directive. The closest enclosing DO directive must have the ORDERED clause specified.

One thread is allowed in an ordered section at a time. Threads are allowed to enter in the order of the loop iterations. No thread can enter an ordered section until it is guaranteed that all previous iterations have completed or will never execute an ordered section. This sequentializes and orders code within ordered sections while allowing code outside the section to run in parallel. ORDERED sections that bind to different DO directives are independent of each other.

The following restrictions apply to the ORDERED directive:

  • An ORDERED directive cannot bind to a DO directive that does not have the ORDERED clause specified.

  • An iteration of a loop with a DO directive must not execute the same ORDERED directive more than once, and it must not execute more than one ORDERED directive.

Data Environment Constructs

This section discusses constructs for controlling the data environment during the execution of parallel constructs.

THREADPRIVATE Directive

The THREADPRIVATE directive makes named common blocks private to a thread but global within the thread. In other words, each thread executing a THREADPRIVATE directive receives its own private copy of the named common blocks, which are then available to it in any routine within the scope of an application.

This directive must appear in the declaration section of the routine after the declaration of the listed common blocks. Each thread gets its own copy of the common block, so data written to the common block by one thread is not directly visible to other threads. During serial portions and MASTER sections of the program, accesses are to the master thread's copy of the common block.

On entry to the first parallel region, data in the THREADPRIVATE common blocks should be assumed to be undefined unless a COPYIN clause is specified on the PARALLEL directive (see “COPYIN Clause” for details).

When a common block that is initialized using DATA statements appears in a THREADPRIVATE directive, each thread's copy is initialized once prior to its first use. For subsequent parallel regions, the data in the THREADPRIVATE common blocks are guaranteed to persist only if the dynamic threads mechanism has been disabled and if the number of threads are the same for all the parallel regions.

For more information about dynamic threads, see the OMP_SET_DYNAMIC library routine and the OMP_DYNAMIC environment variable on the pe_environ(5) man page.

The format of this directive is as follows:

C$OMP THREADPRIVATE(/cb/[,/cb/]...)

The cb argument is the name of the common block to be made private to a thread. Only named common blocks can be made thread private.

The following restrictions apply to the THREADPRIVATE directive:

  • The THREADPRIVATE directive must appear after every declaration of a thread private common block.

  • You cannot use a THREADPRIVATE common block or its constituent variables in any clause other than a COPYIN clause. As a result, they are not permitted in a PRIVATE, FIRSTPRIVATE, LASTPRIVATE, SHARED, or REDUCTION clause. They are not affected by the DEFAULT clause.

Data Scope Attribute Clauses

Several directives accept clauses that allow a user to control the scope attributes of variables for the duration of the construct. Not all of the clauses in this section are allowed on all directives, but the clauses that are valid on a particular directive are included with the description of the directive. Usually, if no data scope clauses are specified for a directive, the default scope for variables affected by the directive is SHARED.

The following clauses to control scope attributes are discusssed in this section:

  • PRIVATE

  • SHARED

  • DEFAULT

  • FIRSTPRIVATE

  • LASTPRIVATE

  • REDUCTION

  • COPYIN

PRIVATE Clause

The PRIVATE clause declares variables to be private to each thread in a team.

This clause has the following format:

PRIVATE(var[, var]...)

The var argument is a named variable or named common block that is accessible in the scoping unit. Subobjects cannot be specified. If a named common block is specified, its name must appear between slashes.

The behavior of a variable declared in a PRIVATE clause is as follows:

  • A new object of the same type is declared once for each thread in the team. The new object is no longer storage-associated with the storage location of the original object.

  • All references to the original object in the lexical extent of the directive construct are replaced with references to the private object.

  • Variables defined as PRIVATE are undefined for each thread on entering the construct and the corresponding shared variable is undefined on exit from a parallel construct.

  • Contents, allocation state, and association status of variables defined as PRIVATE are undefined when they are referenced outside the lexical extent (but inside the dynamic extent) of the construct, unless they are passed as actual arguments to called routines.

SHARED Clause

The SHARED clause makes variables shared among all the threads in a team. All threads within a team access the same storage area for SHARED data.

This clause has the following format:

SHARED(var[, var] ...)

The var argument is a named variable or named common block that is accessible in the scoping unit. Subobjects cannot be specified. If a named common block is specified, its name must appear between slashes.

DEFAULT Clause

The DEFAULT clause allows the user to specify a PRIVATE, SHARED, or NONE default scope attribute for all variables in the lexical extent of any parallel region. Variables in THREADPRIVATE common blocks are not affected by this clause.

This clause has the following format:

DEFAULT(PRIVATE | SHARED | NONE)

The PRIVATE, SHARED, and NONE specifications have the following effects:

  • Specifying DEFAULT(PRIVATE) makes all named objects in the lexical extent of the parallel region, including common block variables but excluding THREADPRIVATE variables, private to a thread as if each variable were listed explicitly in a PRIVATE clause.

  • Specifying DEFAULT(SHARED) makes all named objects in the lexical extent of the parallel region shared among the threads in a team, as if each variable were listed explicitly in a SHARED clause. In the absence of an explicit DEFAULT clause, the default behavior is the same as if DEFAULT(SHARED) were specified.

  • Specifying DEFAULT(NONE) declares that there is no implicit default as to whether variables are PRIVATE or SHARED. In this case, the PRIVATE, SHARED, FIRSTPRIVATE, LASTPRIVATE, or REDUCTION attribute of each variable used in the lexical extent of the parallel region must be specified.

Only one DEFAULT clause can be specified on a PARALLEL directive.

Variables can be exempted from a defined default using the PRIVATE, SHARED, FIRSTPRIVATE, LASTPRIVATE, and REDUCTION clauses. As a result, the following example is valid:

C$OMP PARALLEL DO DEFAULT(PRIVATE), FIRSTPRIVATE(I),SHARED(X),
C$OMP& SHARED(R) LASTPRIVATE(I)

FIRSTPRIVATE Clause

The FIRSTPRIVATE clause provides a superset of the functionality provided by the PRIVATE clause.

This clause has the following format:

FIRSTPRIVATE(var[, var] ...)

The var argument is a named variable or named common block that is accessible in the scoping unit. Subobjects cannot be specified. If a named common block is specified, its name must appear between slashes.

Variables specified are subject to PRIVATE clause semantics as described previously. In addition, private copies of the variables are initialized from the original object existing before the construct.

LASTPRIVATE Clause

The LASTPRIVATE clause provides a superset of the functionality provided by the PRIVATE clause.

When the LASTPRIVATE clause appears on a DO directive, the thread that executes the sequentially last iteration updates the version of the object it had before the construct. When the LASTPRIVATE clause appears in a SECTIONS directive, the thread that executes the lexically last SECTION updates the version of the object it had before the construct. Subobjects that are not assigned a value by the last iteration of the DO or the lexically last SECTION of the SECTIONS directive are undefined after the construct.

This clause has the following format:

LASTPRIVATE(var[, var] ...)

The var argument is a named variable or named common block that is accessible in the scoping unit. Subobjects cannot be specified. If a named common block is specified, its name must appear between slashes.

Each var is subject to the PRIVATE clause semantics described previously.

REDUCTION Clause

This clause performs a reduction on the variables specified, with the operator or the intrinsic specified. These can only be used on scalar variables of INTRINSIC type.

This clause has the following format:

REDUCTION({operator|intrinsic}:var[, var] ...)

Specify one of the following for operator: +, *, -, .AND., .OR., .EQV., or .NEQV. .

Specify one of the following for intrinsic: MAX, MIN, IAND, IOR, or IEOR.

The var argument is a named variable or named common block that is accessible in the scoping unit. Subobjects cannot be specified. Each var must be a named scalar variable of intrinsic type.

Variables that appear in a REDUCTION clause must be SHARED in the enclosing context. A private copy of each var is created for each thread as if the PRIVATE clause had been used. The private copy is initialized according to the operator. If a named common block is specified, its name must appear between slashes.

At the end of the REDUCTION, the shared variable is updated to reflect the result of combining the original value of the (shared) reduction variable with the final value of each of the private copies using the operator specified. The reduction operators are all associative (except for subtraction), and the compiler can freely reassociate the computation of the final value (the partial results of a subtraction reduction are added to form the final value).

The value of the shared variable becomes undefined when the first thread reaches the containing clause, and it remains so until the reduction computation is complete. Normally, the computation is complete at the end of the REDUCTION construct; however, if the REDUCTION clause is used on a construct to which NOWAIT is also applied, the shared variable remains undefined until a barrier synchronization has been performed to ensure that all the threads have completed the REDUCTION clause.

The REDUCTION clause is intended to be used on a region or work-sharing construct in which the reduction variable is used only in reduction statements with one of the following forms:

  • x = x operator expr

  • x = expr operator x (except for subtraction)

  • x = intrinsic (x,expr)

  • x = intrinsic (expr, x)

Some reductions can be expressed in other forms. For instance, a MAX reduction might be expressed as follows:

IF (x .LT. expr) x = expr

Alternatively, the reduction might be hidden inside a subroutine call. The user should be careful that the operator specified in the REDUCTION clause matches the reduction operation.

The following table lists the operators and intrinsics that are valid and their canonical initialization values. The actual initialization value will be consistent with the data type of the reduction variable.

Operator 

Initialization

+ 

0

* 

1

_ 

0

.AND. 

.TRUE.

.OR. 

.FALSE.

.EQV. 

.TRUE.

.NEQV. 

.FALSE.

MAX 

Smallest representable number

MIN 

Largest representable number

IAND 

All bits on

IOR 

0

IEOR 

0

Any number of reduction clauses can be specified on the directive, but a variable can appear only once in a REDUCTION clause for that directive. The following is an example:

C$OMP DO REDUCTION(+: A, Y) REDUCTION(.OR.: AM)

COPYIN Clause

The COPYIN clause applies only to common blocks that are declared THREADPRIVATE discussed in “THREADPRIVATE Directive”. A COPYIN clause on a parallel region specifies that the data in the master thread of the team be copied to the thread private copies of the common block at the beginning of the parallel region.

This clause has the following format:

COPYIN(var[, var] ...)

The var argument is a named variable or named common block that is accessible in the scoping unit. Subobjects cannot be specified. If a named common block is specified, its name must appear between slashes. It is not necessary to specify a whole common block to be copied in.

Example. In the following example, the common blocks BLK1 and FIELDS are specified as THREADPRIVATE, but only one of the variables in common block FIELDS is specified to be copied in:

      COMMON /BLK1/ SCRATCH
      COMMON /FIELDS/ XFIELD, YFIELD, ZFIELD
C$OMP THREADPRIVATE(/BLK1/, /FIELDS/)
C$OMP PARALLEL DEFAULT(PRIVATE) COPYIN(/BLK1/,ZFIELD)

Data Scope Rules and Restrictions

The following rules and restrictions apply with respect to data scope:

  • Sequential DO loop control variables in the lexical extent of a PARALLEL region that would otherwise be SHARED based on default rules are automatically made private on the PARALLEL directive. Sequential DO loop control variables with no enclosing PARALLEL region are not classified automatically. It is the user's responsibility to guarantee that these indexes are private if the containing procedures are called from a PARALLEL region.

    All implied DO loop control variables are automatically made private at the enclosing implied DO construct.

  • Variables that are made private in a parallel region cannot be made private again on an enclosed work-sharing directive. As a result, variables that appear in the PRIVATE, FIRSTPRIVATE, LASTPRIVATE, and REDUCTION clauses on a work-sharing directive have shared scope in the enclosing parallel region.

  • A variable that appears in a PRIVATE, FIRSTPRIVATE, LASTPRIVATE, or REDUCTION clause must be definable.

  • PRIVATE or SHARED attributes can be declared for a Cray pointer but not for the pointee. The scope attribute for the pointee is determined at the point of pointer definition. You cannot declare a scope attribute for a pointee. Cray pointers cannot be specified in FIRSTPRIVATE or LASTPRIVATE clauses.

  • Scope clauses apply only to variables in the static extent of the directive on which the clause appears, with the exception of variables passed as actual arguments. Local variables in called routines that do not have the SAVE attribute are PRIVATE. Common blocks in called routines in the dynamic extent of a parallel region always have an implicit SHARED attribute, unless they are THREADPRIVATE common blocks.

  • When a named common block is declared as PRIVATE, FIRSTPRIVATE, or LASTPRIVATE, none of its constituent elements may be declared in another scope attribute. When individual members of a common block are privatized, the storage of the specified variables is no longer associated with the storage of the common block itself.

  • Variables that are not allowed in the PRIVATE and SHARED clauses are not affected by DEFAULT(PRIVATE) or DEFAULT(SHARED) clauses, respectively.

  • Clauses can be repeated as needed, but each variable can appear explicitly in only one clause per directive; the exception is that a variable can be specified as both FIRSTPRIVATE and LASTPRIVATE.

Variables affected by the DEFAULT clause can be listed explicitly in a clause to override the default specification.

Directive Binding

Some directives are bound to other directives. A binding specifies the way in which one directive is related to another. For instance, a directive is bound to a second directive if it can appear DEFAULT in the dynamic extent of that second directive. The following rules apply with respect to the dynamic binding of directives:

  • The DO, SECTIONS, SINGLE, MASTER, and BARRIER directives bind to the dynamically enclosing PARALLEL directive, if one exists.

  • The ORDERED directive binds to the dynamically enclosing DO directive.

  • The ATOMIC directive enforces exclusive access with respect to ATOMIC directives in all threads, not just the current team.

  • The CRITICAL directive enforces exclusive access with respect to CRITICAL directives in all threads, not just the current team.

  • A directive can never bind to any directive outside the closest enclosing PARALLEL.

Directive Nesting

The following rules apply to the dynamic nesting of directives:

  • A PARALLEL directive dynamically inside another PARALLEL directive logically establishes a new team, which is composed of only the current thread.

  • DO, SECTIONS, and SINGLE directives that bind to the same PARALLEL directive cannot be nested one inside the other.

  • DO, SECTIONS, and SINGLE directives are not permitted in the dynamic extent of CRITICAL and MASTER directives.

  • BARRIER directives are not permitted in the dynamic extent of DO, SECTIONS, SINGLE, MASTER, and CRITICAL directives.

  • MASTER directives are not permitted in the dynamic extent of DO, SECTIONS, and SINGLE directives.

  • ORDERED sections are not allowed in the dynamic extent of CRITICAL sections.

  • Any directive set that is legal when executed dynamically inside a PARALLEL region is also legal when executed outside a parallel region. When executed dynamically outside a user-specified parallel region, the directive is executed with respect to a team composed of only the master thread.