#pragma omp atomic
Purpose
The omp atomic directive allows access of a specific memory location atomically. It ensures that race conditions are avoided through direct control of concurrent threads that might read or write to or from the particular memory location. With the omp atomic directive, you can write more efficient concurrent algorithms with fewer locks.
Syntax
.-update--. >>-#--pragma--omp atomic--+---------+---------------------------> +-read----+ +-write---+ '-capture-' >--+-expression_statement-+------------------------------------>< '-structured_block-----'
where expression_statement is an expression statement of scalar type, and structured_block is a structured block of two expression statements.
Clauses
- update
- Updates the value of a variable atomically. Guarantees that
only one thread at a time updates the shared variable, avoiding
errors from simultaneous writes to the same variable. An omp atomic directive
without a clause is equivalent to an omp atomic update.Note: Atomic updates cannot write arbitrary data to the memory location, but depend on the previous data at the memory location.
- read
- Reads the value of a variable atomically. The value of a shared variable can be read safely, avoiding the danger of reading an intermediate value of the variable when it is accessed simultaneously by a concurrent thread.
- write
- Writes the value of a variable atomically. The value of a shared variable can be written exclusively to avoid errors from simultaneous writes.
- capture
- Updates the value of a variable while capturing the original or final value of the variable atomically.
Directive clause | expression_statement | structured_block |
---|---|---|
update (equivalent to no clause) |
x++; x--; ++x; --x; x binop = expr; x = x binop expr; x = expr binop x; |
|
read | v = x; |
|
write | x = expr; |
|
capture | v = x++; v = x--; v = ++x; v = --x; v = x binop = expr; v = x = x binop expr; v = x = expr binop x; |
{v = x; x binop = expr;} {v = x; xOP;} {v = x; OPx;} {x binop = expr; v = x;} {xOP; v = x;} {OPx; v = x;} {v = x; x = x binop expr;} {x = x binop expr; v = x;} {v = x; x = expr binop x;} {x = expr binop x; v = x;} {v = x; x = expr;}1 |
Note:
|
- x, v
- are both lvalue expressions with scalar type.
- expr
- is an expression of scalar type that does not reference x.
- binop
- is one of the following binary operators:
+ * - / & ^ | << >>
- OP
- is one of ++ or --.
Usage
Objects that can be updated in parallel and that might be subject to race conditions should be protected with the omp atomic directive.
All atomic accesses to the storage locations designated by x throughout the program should have a compatible type.
Within an atomic region, multiple syntactic occurrences of x must designate the same storage location.
All accesses to a certain storage location throughout a concurrent program must be atomic. A non-atomic access to a memory location might break the expected atomic behavior of all atomic accesses to that storage location.
Neither v nor expr can access the storage location that is designated by x.
Neither x nor expr can access the storage location that is designated by v.
All accesses to the storage location designated by x are atomic. Evaluations of the expression expr, v, x are not atomic.
For atomic capture access, the operation of writing the captured value to the storage location represented by v is not atomic.
Examples
Example 1: Atomic update
extern float x[], *p = x, y;
/* Protect against race conditions among multiple updates. */
#pragma omp atomic
x[index[i]] += y;
/* Protect against race conditions with updates through x. */
#pragma omp atomic
p[i] -= 1.0f;
Example 2: Atomic read, write, and update
extern int x[10];
extern int f(int);
int temp[10], i;
for(i = 0; i < 10; i++)
{
#pragma omp atomic read
temp[i] = x[f(i)];
#pragma omp atomic write
x[i] = temp[i]*2;
#pragma omp atomic update
x[i] *= 2;
}
Example 3: Atomic capture
extern int x[10];
extern int f(int);
int temp[10], i;
for(i = 0; i < 10; i++)
{
#pragma omp atomic capture
temp[i] = x[f(i)]++;
#pragma omp atomic capture
{
temp[i] = x[f(i)]; //the two occurences of x[f(i)] must evaluate to the
x[f(i)] -= 3; //same memory location, otherwise behavior is undefined.
}
}