OpenMP* Fortran Compiler Directive: Ensures that a specific memory location is updated atomically; this prevents the possibility of multiple threads simultaneously reading and writing the specific memory location.
!$OMP ATOMIC [type-clause[[,] clause]] -or- !$OMP ATOMIC [clause[[,] type-clause]]
block
!$OMP END ATOMIC
type-clause |
(Optional) Is one of the following:
READ
If !$OMP ATOMIC READ is specified, block is a capture-statement.
WRITE
If !$OMP ATOMIC WRITE is specified, block is a write-statement.
UPDATE
If !$OMP ATOMIC UPDATE is specified, block is an update-statement.
CAPTURE
If !$OMP ATOMIC CAPTURE is specified, block is either one update-statement and one capture-statement in either order, or one capture-statement followed by one write-statement in that order.
For details on the effects of these clauses,
see the table in the Description section.
|
clause |
(Optional) Is the following:
|
capture-statement |
Is an expression in the form v = x.
|
write-statement |
Is an expression in the form x = expr.
|
update-statement |
Is an expression with one of the following forms:
x = x operator expr x = expr operator x x = intrinsic (x, expr-list) x = intrinsic (expr-list, x) The following rules apply:
Operators in expr must have precedence equal to or greater than the precedence of operator.
xoperatorexpr must be mathematically equivalent to x operator (expr). This requirement is satisfied if the operators in expr have precedence greater than operator, or by using parentheses around expr or subexpressions of expr.
exproperatorx must be mathematically equivalent to (expr) operator x. This requirement is satisfied if the operators in expr have precedence equal to or greater than operator, or by using parentheses around expr or subexpressions of expr.
All assignments must be intrinsic assignments.
|
x, v |
Are scalar variables of intrinsic
type. During execution of an atomic region, all
references to storage location x
must specify the same storage location.
v must not access the same storage location as x.
|
expr, expr-list |
The expr is a scalar expression. The expr-list is a comma-separated, non-empty list of scalar expressions. They must not access the same storage location as x.
If intrinsic is IAND, IOR, or IEOR, only one expression can appear in expr-list.
|
operator |
Is one of the following intrinsic operators: +, *, -, /, ,AND., ,OR., .EQV., or .NEQV..
|
intrinsic |
Is one of the following intrinsic procedures: MAX, MIN, IAND, IOR, or IEOR.
|
If !$OMP ATOMIC is specified with no type-clause or no clause, it is the same as specifying !$OMP ATOMIC UPDATE.
If !$OMP ATOMIC CAPTURE is specified, you must include an !$OMP END ATOMIC directive following the block. Otherwise, the !$OMP END ATOMIC directive is optional.
The binding thread set for an atomic region is
all threads. Atomic regions enforce exclusive access with respect
to other atomic regions that access the same storage location x among all the threads in the program without regard to the
teams to which the threads belong.
Note that the following restriction applies to
the ATOMIC directive:
The following table describes what happens when
you specify one of the clauses in an ATOMIC construct.
Clause |
Result |
READ |
Causes an atomic read of the location designated by x regardless of the native machine word size.
|
WRITE |
Causes an atomic write of the location designated by x regardless of the native machine word size.
|
UPDATE |
Causes an atomic
update of the location designated by x using the designated
operator or intrinsic. The following rules also apply:
The evaluation of expr or expr-list
need not be atomic with respect to the read or write of the
location designated by x.
No task scheduling points are allowed between the
read and the write of the location designated by
x.
|
CAPTURE |
Causes an atomic update of the location
designated by x using the designated operator or intrinsic
while also capturing the original or final value of the location
designated by x in v. The following
rules also apply:
The original or final value of the location
designated by x is written in the location designated by
v, depending on the form of the ATOMIC construct, structured
block, or statements, following the usual language
semantics.
Only the read and write of the location designated
by x are performed mutually atomically.
The evaluation of expr or expr-list,
and the write to the location designated by v do not need to
be atomic with respect to the read or write of the location
designated by x.
No task scheduling points are allowed between
the read and the write of the location designated by
x.
|
SEQ_CST |
Causes the atomically performed operation to include an implicit flush operation without a list.
If this clause is specified, the construct is a
sequentially consistent atomic construct.
Unlike non-sequentially consistent atomic
constructs, sequentially consistent atomic constructs preserve the
interleaving (sequentially consistent) behavior of correct,
data-race-free programs.
However, they are not designed to replace the
FLUSH directive as a mechanism to enforce ordering for
non-sequentially consistent atomic constructs, and attempts to do
so require extreme caution.
For example, a sequentially consistent atomic
write construct may appear to be reordered with a subsequent
non-sequentially consistent atomic write construct, since such
reordering would not be observable by a correct program if the
second write were outside an ATOMIC directive.
|
Any combination of two or more of these atomic
constructs enforces mutually exclusive access to the locations
designated by x.
A race condition exists when two unsynchronized
threads access the same shared variable with at least one thread
modifying the variable; this can cause unpredictable results. To
avoid race conditions, all accesses of the locations designated by
x that could potentially occur in parallel must be protected with
an ATOMIC construct.
Atomic regions do not guarantee exclusive
access with respect to any accesses outside of atomic regions to
the same storage location x even if those accesses occur
during a CRITICAL or ORDERED region, while an OpenMP lock is owned
by the executing task, or during the execution of a REDUCTION
clause.
However, other OpenMP* synchronization can
ensure the desired exclusive access. For example, a BARRIER
directive following a series of atomic updates to x guarantees that
subsequent accesses do not form a race condition with the atomic
accesses.
例
The following example shows a way to avoid race conditions by using ATOMIC to protect all simultaneous updates of the location by multiple threads.
Since the ATOMIC directive below applies only to the statement immediately following it, elements of Y are not updated atomically.
REAL FUNCTION FOO1(I)
INTEGER I
FOO1 = 1.0 * I
RETURN
END FUNCTION FOO1
REAL FUNCTION FOO2(I)
INTEGER I
FOO2 = 2.0 * I
RETURN
END FUNCTION FOO2
SUBROUTINE SUB(X, Y, INDEX, N)
REAL X(*), Y(*)
INTEGER INDEX(*), N
INTEGER I
!$OMP PARALLEL DO SHARED(X, Y, INDEX, N)
DO I=1,N
!$OMP ATOMIC UPDATE
X(INDEX(I)) = X(INDEX(I)) + FOO1(I)
Y(I) = Y(I) + FOO2(I)
ENDDO
END SUBROUTINE SUB
PROGRAM ATOMIC_DEMO
REAL X(1000), Y(10000)
INTEGER INDEX(10000)
INTEGER I
DO I=1,10000
INDEX(I) = MOD(I, 1000) + 1
Y(I) = 0.0
ENDDO
DO I = 1,1000
X(I) = 0.0
ENDDO
CALL SUB(X, Y, INDEX, 10000)
END PROGRAM ATOMIC_DEMO
The following non-conforming example demonstrates the restriction on the ATOMIC construct:
SUBROUTINE ATOMIC_INCORRECT()
INTEGER:: I
REAL:: R
EQUIVALENCE(I,R)
!$OMP PARALLEL
!$OMP ATOMIC UPDATE
I = I + 1
!$OMP ATOMIC UPDATE
R = R + 1.0
! The above is incorrect because I and R reference the same location
! but have different types
!$OMP END PARALLEL
END SUBROUTINE ATOMIC_INCORRECT