Mutexes in Co-array Fortran

In the previous example, we saw how to manage simple counter state using atomic operations. For more complex state, we can use a critical section to safely access data across multiple images.

module container_mod
  use iso_fortran_env
  implicit none

  type :: container
    integer :: counters(2)[*]
  end type container

contains

  subroutine inc(this, name)
    type(container), intent(inout) :: this
    integer, intent(in) :: name
    
    critical
      this%counters(name) = this%counters(name) + 1
    end critical
  end subroutine inc

end module container_mod

program mutexes
  use container_mod
  use iso_fortran_env
  implicit none

  type(container) :: c
  integer :: i

  c%counters = 0

  do i = 1, 10000
    call inc(c, 1)
  end do

  sync all

  if (this_image() == 1) then
    do i = 1, 10000
      call inc(c, 1)
    end do

    do i = 1, 10000
      call inc(c, 2)
    end do

    print *, "Counters:", c%counters
  end if

end program mutexes

In this Co-array Fortran version:

  1. We define a container type that holds an array of counters as a co-array.

  2. The inc subroutine increments a named counter within a critical section to ensure thread safety.

  3. In the main program, we initialize the counters to zero.

  4. We then perform increments across multiple images:

    • All images increment the first counter 10000 times.
    • Image 1 additionally increments the first counter another 10000 times and the second counter 10000 times.
  5. We use sync all to ensure all images have completed their operations before printing the results.

  6. Finally, we print the counters from image 1.

To run the program:

$ gfortran -fcoarray=lib mutexes.f90 -o mutexes
$ ./mutexes
Counters: 20000 10000

This example demonstrates how to use critical sections in Co-array Fortran to safely manage shared state across multiple images, which is analogous to using mutexes in other languages.