Mutexes in Fortran
In the previous example, we saw how to manage simple counter state using atomic operations. For more complex state, we can use a mutex to safely access data across multiple threads.
module mutexes
use, intrinsic :: iso_fortran_env
use omp_lib
implicit none
type container
integer :: mutex
integer, allocatable :: counters(:)
end type container
contains
subroutine inc(c, name)
type(container), intent(inout) :: c
integer, intent(in) :: name
call omp_set_lock(c%mutex)
c%counters(name) = c%counters(name) + 1
call omp_unset_lock(c%mutex)
end subroutine inc
subroutine do_increment(c, name, n)
type(container), intent(inout) :: c
integer, intent(in) :: name, n
integer :: i
do i = 1, n
call inc(c, name)
end do
end subroutine do_increment
end module mutexes
program main
use mutexes
implicit none
type(container) :: c
integer :: i
allocate(c%counters(2))
c%counters = 0
call omp_init_lock(c%mutex)
!$omp parallel sections
!$omp section
call do_increment(c, 1, 10000)
!$omp section
call do_increment(c, 1, 10000)
!$omp section
call do_increment(c, 2, 10000)
!$omp end parallel sections
call omp_destroy_lock(c%mutex)
print *, "Counters:", c%counters
deallocate(c%counters)
end program main
In this Fortran implementation:
We define a
container
type that holds a mutex (implemented as an integer for use with OpenMP) and an array of counters.The
inc
subroutine increments a specific counter, using OpenMP’s lock routines to ensure thread safety.The
do_increment
subroutine callsinc
in a loop, similar to the original example.In the main program, we initialize the container, create parallel sections to run the increment operations concurrently, and then print the results.
We use OpenMP for parallelism, which is a common approach in Fortran for shared-memory parallelism.
Instead of a map, we use a simple integer array for counters. The index of the array represents the “name” of the counter.
To compile and run this program, you would typically use a command like:
$ gfortran -fopenmp mutexes.f90 -o mutexes
$ ./mutexes
Counters: 20000 10000
This output shows that the counters were updated as expected, with the first counter (index 1) incremented to 20000 and the second counter (index 2) to 10000.
Note that Fortran doesn’t have built-in support for maps or hash tables, so we’ve simplified the example to use array indices instead of string keys. Also, Fortran doesn’t have a direct equivalent to goroutines, so we’ve used OpenMP parallel sections to achieve similar concurrency.
In the next example, we’ll look at implementing this same state management task using only threading and message passing.