Critical Sections and Atomic Operations

Critical sections are blocking; no thread can enter a critical section until the thread executing the block has exited. It is illegal to jump into or out of a critical section; the code block must be executed in its entirely by all threads.

It is possible to use named critical sections to partially minimize the serialization, but this is beyond our scope.

Critical sections can surround any block of code of any length. However, a frequent pattern is the need for only one operation to be performed one thread at a time.

In the special circumstances of the pi-computing code, we can use an atomic operation rather than a critical section. Atomic operations are limited to “storage” access, which in this context means memory. The operation can read the storage location, write to it, or update it. These specifics can be added as clauses to the construct, but are not usually necessary and were added in recent versions of the standard.

Without a clause (or when the clause is update), the following operations are supported:

x++;  // C/C++
x--;  // C/C++
++x;  // C/C++
--x;  // C/C++
x binop= expr
x = x binop expr
x = expr binop x

where binop is one of one of +, *, -, /, &, ^, |, <<, or >>. The operation must be supported by the underlying language. The expr is an arithmetic expression with the permitted operations.

The atomic directive applies only to the statement following it.

Atomic operations can have lower overhead than using a critical section for the same statement, and if the architecture supports it they can use hardware atomic operations to further reduce overhead. Also, if two independent statements are critical, they can each be atomic and different threads can execute them at the same time, as long as only one thread performs the operation.

Atomic operations still serialize the code, however.

Syntax

C/C++

#pragma omp atomic <clause>

Fortran

!$omp atomic <clause>
! optional
!$omp end atomic

The end is optional since atomic is only valid for the following statement.

Python Omp4py does not seem to have fully implemented this yet.

Exercise

Modify the pi code to use an atomic construct.

Solutions

C

Contents of omp_atomic.c

#include <stdlib.h>
#include <stdio.h>
#include <omp.h>

int main() {

    double area, pi, x;
    int n;

    n=1000;

    area=0.0;
    for (int i=0; i< n; i++) {
        x=(i+0.5)/n;
        #pragma omp atomic
        area+=4.0/(1.0+x*x);
    }

    pi=area/n;
    printf("Pi is %f\n",pi);

    return(0);
}

Download omp_atomic.c file

Fortran

Contents of omp_atomic.f90

program pie
use omp_lib
implicit none

double precision :: area, pi, x
integer          :: i, n
integer          :: nthreads

   n=10000
   area=0.0

!$omp parallel do private(x) 
    do i=1,n
       x=(i+0.5d0)/n
       !$omp atomic
       area=area+4.0/(1.0d0+x**2)
    enddo
!$omp end parallel do

    pi=area/n
    write(*,'(a,f9.6)') "Pi is ", pi

end program

Download omp_atomic.f90 file

Previous
Next
© 2026 The Rector and Visitors of the University of Virginia