| Cray C and C++ Reference Manual - S-2179-51 | ||
|---|---|---|
| Prev Section | Chapter 4. OpenMP C API Directives | Next Section |
The following sections describe the:
master construct
critical construct
barrier directive
atomic construct
flush directive
ordered construct
The master directive identifies a construct that specifies a structured block that is executed by the master thread of the team. The syntax of the master directive is as follows:
#pragma omp master new-line
structured-block |
Other threads in the team do not execute the associated structured block. There is no implied barrier either on entry to or exit from the master construct.
The critical directive identifies a construct that restricts execution of the associated structured block to a single thread at a time. The syntax of the critical directive is as follows:
#pragma omp critical [(name)] new-line
structured-block |
An optional name may be used to identify the critical region. Identifiers used to identify a critical region have external linkage and are in a name space which is separate from the name spaces used by labels, tags, members, and ordinary identifiers.
A thread waits at the beginning of a critical region until no other thread is executing a critical region (anywhere in the program) with the same name. All unnamed critical directives map to the same unspecified name.
The barrier directive synchronizes all the threads in a team. When encountered, each thread in the team waits until all of the others have reached this point. The syntax of the barrier directive is as follows:
#pragma omp barrier new-line |
After all threads in the team have encountered the barrier, each thread in the team begins executing the statements after the barrier directive in parallel.
Note that because the barrier directive does not have a C language statement as part of its syntax, there are some restrictions on its placement within a program. The example below illustrates these restrictions.
/* ERROR - The barrier directive cannot be the immediate
* substatement of an if statement
*/
if (x!=0)
#pragma omp barrier
...
/* OK - The barrier directive is enclosed in a
* compound statement.
*/
if (x!=0) {
#pragma omp barrier
} |
The atomic directive ensures that a specific memory location is updated atomically, rather than exposing it to the possibility of multiple, simultaneous writing threads. The syntax of the atomic directive is as follows:
#pragma omp atomic new-line
expression-stmt |
The expression statement must have one of the following forms:
x binop= expr
x++
++x
x--
--x
In the preceding expressions:
x is an lvalue expression with scalar type
expr is an expression with scalar type, and it does not reference the object designated by x
binop is not an overloaded operator and is one of +, *, -, /, &, ^, |, <<, or >>
Although it is implementation-defined whether an implementation replaces all atomic directives with critical directives that have the same unique name, the atomic directive permits better optimization. Often hardware instructions are available that can perform the atomic update with the least overhead.
Only the load and store of the object designated by x are atomic; the evaluation of expr is not atomic. To avoid race conditions, all updates of the location in parallel should be protected with the atomic directive, except those that are known to be free of race conditions.
Restrictions to the atomic directive are as follows:
All atomic references to the storage location x throughout the program are required to have a compatible type
Examples:
extern float a[], *p = a, b;
/* Protect against races among multiple updates. */
#pragma omp atomic
a[index[i]] += b;
/* Protect against races with updates through a. */
#pragma omp atomic
p[i] -= 1.0f;
extern union {int n; float x;} u;
/* ERROR - References through incompatible types. */
#pragma omp atomic
u.n++;
#pragma omp atomic
u.x -= 1.0f; |
The flush directive, whether explicit or implied, specifies a cross-thread sequence point at which the implementation is required to ensure that all threads in a team have a consistent view of certain objects (specified below) in memory. This means that previous evaluations of expressions that reference those objects are complete and subsequent evaluations have not yet begun. For example, compilers must restore the values of the objects from registers to memory, and hardware may need to flush write buffers to memory and reload the values of the objects from memory.
The syntax of the flush directive is as follows:
#pragma omp flush [(variable-list)]] new-line |
If the objects that require synchronization can all be designated by variables, then those variables can be specified in the optional variable-list. If a pointer is present in the variable-list, the pointer itself is flushed, not the object the pointer refers to.
A flush directive without a variable-list synchronizes all shared objects except inaccessible objects with automatic storage duration. (This is likely to have more overhead than a flush with a variable-list.) A flush directive without a variable-list is implied for the following directives:
barrier
At entry to and exit from critical
At entry to and exit from ordered
At entry to and exit from parallel
At exit from for
At exit from sections
At exit from single
At entry to and exit from parallel for
At entry to and exit from parallel sections
The directive is not implied if a nowait clause is present. It should be noted that the flush directive is not implied for any of the following:
At entry to for
At entry to or exit from master
At entry to sections
At entry to single
A reference that accesses the value of an object with a volatile-qualified type behaves as if there were a flush directive specifying that object at the previous sequence point. A reference that modifies the value of an object with a volatile-qualified type behaves as if there were a flush directive specifying that object at the subsequent sequence point.
Note that because the flush directive does not have a C language statement as part of its syntax, there are some restrictions on its placement within a program. The example below illustrates these restrictions.
/* ERROR - The flush directive cannot be the immediate
* substatement of an if statement.
*/
if (x!=0)
#pragma omp flush (x)
...
/* OK - The flush directive is enclosed in a
* compound statement
*/
if (x!=0) {
#pragma omp flush (x)
} |
Restrictions to the flush directive are as follows:
A variable specified in a flush directive must not have a reference type.
The structured block following an ordered directive is executed in the order in which iterations would be executed in a sequential loop. The syntax of the ordered directive is as follows:
#pragma omp ordered new-line
structured-block |
An ordered directive must be within the dynamic extent of a for or parallel for construct. The for or parallel for directive to which the ordered construct binds must have an ordered clause specified as described in Section 4.4.1. In the execution of a for or parallel for construct with an ordered clause, ordered constructs are executed strictly in the order in which they would be executed in a sequential execution of the loop.
There is one restriction to the ordered directive. An iteration of a loop with a for construct must not execute the same ordered directive more than once, and it must not execute more than one ordered directive.
| Prev Section | Table of Contents | Title Page | Index | Next Section |
| Combined Parallel Work-sharing Constructs | Up one level | Data Environment |