9. Synchronization#

The barrier construct is a stand-alone directive that requires all threads of a team (within a contention group) to execute the barrier and complete execution of all tasks within the region, before continuing past the barrier.

The critical construct is a directive that contains a structured block. The construct allows only a single thread at a time to execute the structured block (region). Multiple critical regions may exist in a parallel region, and may act cooperatively (only one thread at a time in all critical regions), or separately (only one thread at a time in each critical regions when a unique name is supplied on each critical construct). An optional (lock) hint clause may be specified on a named critical construct to provide the OpenMP runtime guidance in selection a locking mechanism.

On a finer scale the atomic construct allows only a single thread at a time to have atomic access to a storage location involving a single read, write, update or capture statement, and a limited number of combinations when specifying the capture atomic-clause clause. The atomic-clause clause is required for some expression statements, but is not required for update statements. The memory-order clause can be used to specify the degree of memory ordering enforced by an atomic construct. From weakest to strongest, they are relaxed (the default), acquire and/or release clauses (specified with acquire, release, or acq_rel), and seq_cst. Please see the details in the atomic Construct subsection of the Directives chapter in the OpenMP Specifications document.

The ordered construct either specifies a structured block in a loop, simd, or loop SIMD region that will be executed in the order of the loop iterations. The ordered construct sequentializes and orders the execution of ordered regions while allowing code outside the region to run in parallel.

Since OpenMP 4.5 the ordered construct can also be a stand-alone directive that specifies cross-iteration dependences in a doacross loop nest. The depend clause uses a sink dependence-type , along with an iteration vector argument (vec) to indicate the iteration that satisfies the dependence. The depend clause with a source dependence-type specifies dependence satisfaction.

The flush directive is a stand-alone construct for enforcing consistency between a thread’s view of memory and the view of memory for other threads (see the Memory Model chapter of this document for more details). When the construct is used with an explicit variable list, a strong flush that forces a thread’s temporary view of memory to be consistent with the actual memory is applied to all listed variables. When the construct is used without an explicit variable list and without a memory-order clause, a strong flush is applied to all locally thread-visible data as defined by the base language, and additionally the construct provides both acquire and release memory ordering semantics. When an explicit variable list is not present and a memory-order clause is present, the construct provides acquire and/or release memory ordering semantics according to the memory-order clause, but no strong flush is performed. A resulting strong flush that applies to a set of variables effectively ensures that no memory (load or store) operation for the affected variables may be reordered across the flush directive.

General-purpose routines provide mutual exclusion semantics through locks, represented by lock variables. The semantics allows a task to set , and hence own a lock, until it is unset by the task that set it. A nestable lock can be set multiple times by a task, and is used when in code requires nested control of locks. A simple lock can only be set once by the owning task. There are specific calls for the two types of locks, and the variable of a specific lock type cannot be used by the other lock type.

Any explicit task will observe the synchronization prescribed in a barrier construct and an implied barrier. Also, additional synchronizations are available for tasks. All children of a task will wait at a taskwait (for their siblings to complete). A taskgroup construct creates a region in which the current task is suspended at the end of the region until all sibling tasks, and their descendants, have completed. Scheduling constraints on task execution can be prescribed by the depend clause to enforce dependence on previously generated tasks. More details on controlling task executions can be found in the Tasking Chapter in the OpenMP Specifications document.