The ATOMIC directive ensures that a specific memory location is updated dynamically; this prevents the possibility of multiple, simultaneous writing threads. It takes the following form:
The ATOMIC directive permits optimization beyond that of the critical section around the assignment. An implementation can replace ATOMIC directives by enclosing each statement in a critical section. The critical section (or sections) must use the same unique name.
The ATOMIC 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:
All references to storage location x must have the same type and type parameters.
Only the loading and storing of x are dynamic; the evaluation of expr is not dynamic. To avoid race conditions (or concurrency races), all updates of the location in parallel must be protected using the ATOMIC directive, except those that are known to be free of race conditions. The function intrinsic, the operator operator, and the assignment must be the intrinsic function, operator, and assignment.
Examples
The following example shows a way to avoid race conditions by using ATOMIC to protect all simultaneous updates of the location by multiple threads:
c$OMP PARALLEL DO DEFAULT(PRIVATE) SHARED(X,Y,INDEX,N)
DO I=1,N
CALL WORK(XLOCAL, YLOCAL)
c$OMP ATOMIC
X(INDEX(I)) = X(INDEX(I)) + XLOCAL
Y(I) = Y(I) + YLOCAL
END DO
Since the ATOMIC directive applies only to the statement immediately following it, note that Y is not updated atomically.