Intel® Advisor User Guide

ID 766448
Date 3/22/2024
Public

A newer version of this document is available. Customers should click here to go to the newest version.

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;
                }