Intel® Advisor User Guide

ID 766448
Date 3/22/2024
Public
Document Table of Contents

Advanced OpenMP Atomic Operations

This topic provides advanced examples of OpenMP* atomic operations.

These advanced atomic operations use clauses after the atomic construct, such as read, write, update, capture, and seq_cst. If you do not add a clause after atomic, the default is update.

Because these clauses are part of OpenMP 3.1 and 4.0 specification, you need a compiler that supports these advanced atomic clauses, such as the Intel® Fortran Compiler Classic.

TIP:
After you rewrite your code to use OpenMP* parallel framework, you can analyze its performance with Intel® Advisor perspectives. Use the Vectorization and Code Insights perspective to analyze how well you OpenMP code is vectorized or use the Offload Modeling perspective to model its performance on a GPU.

Example Using the read and write Clauses

The following C/C++ example uses separate read and write clauses:

int atomic_read(const int *x)
{
  int value;
  /* Ensure that the entire value of *x is read atomically. */ 
  /* No part of *x can change during the read operation. */
#pragma omp atomic read
  value = *x;
  return value;
}
void atomic_write(int *x, int value)
{
  /* Ensure that value is stored atomically into *x.   */
  /* No part of *x can change until after the entire write operation has completed. */
  #pragma omp atomic write
  *x = value;
}

The following Fortran example uses the read and write clauses:

function atomic_read(x)
   integer :: atomic_read
   integer, intent(in) :: x
! Ensure that the entire value of x is read atomically. No part of x can change during 
! the read operation.

!$omp atomic read
   atomic_read = x
   return
end function atomic_read
subroutine atomic_write(x, value)
  integer, intent(out) :: x
  integer, intent(in) :: value
  ! Ensure that value is stored atomically into x. No part of x can change
  ! until after the entire write operation has completed.
  !$omp atomic write
  x = value
end subroutine atomic_write

Example Using the Basic capture Clause

The following C/C++ example uses the capture clause:

#pragma omp parallel for shared (pos)
     for (int i=0; i < size; i++) {
          
          if (isValid(data[i])) {
                int tmpPos;
                // Using omp atomic capture pragma 
                #pragma omp atomic capture
                {
                     tmpPos = pos;
                     pos =  pos+1;
                }
                //Pack all selected element' indices in index; exact order of indices values is not important.
                index[tmpPos] = i;
          }
     }

Example Using the Swap Form of the capture Clause

The capture clause example above might be modified to use the following code snippet:

//with introduction of “atomic swap” you can also use forms like:
                     newPos = foo();
       .
       .
       .
#pragma omp atomic capture
                {
                     tmpPos = pos;
                     pos =  newPos;
                }