POSIX Threads
In modern Fortran, multi-processing may be achieved by accessing POSIX
Threads (pthreads) on Unix-like operating systems. The
fortran-unix library
provides interface bindings to the C structure pthread_t
, as well
as the C functions pthread_create()
and
pthread_join()
. For joined access to common resources we can use
mutexes to lock critical sections.
fortran-unix
Clone the fortran-unix repository and build the static library
libfortran-unix.a
:
$ git clone https://github.com/interkosmos/fortran-unix
$ cd fortran-unix/
$ make freebsd
On Linux, run make linux
instead. Import the module
unix
and link your Fortran application against
libfortran-unix.a
, and additionally against -lpthread
to access POSIX Threads.
Example
Fortran subroutines which will run inside a thread must have the
recursive
and the bind(c)
attribute. The routines are
given an argument that contains a pointer to arbitrary client data passed by
the c_pthread_create()
function. The pointer has to be converted
to the appropriate Fortran type first to be accessible. Due to the
bind(c)
attribute, it is required to specify whether an argument
is passed by reference (default) or by value (dummy argument attribute
value
) to the routine.
! example.f90
program main
use :: unix
implicit none
integer, parameter :: NTHREADS = 3
integer :: i, rc
integer, target :: routines(NTHREADS) = [ (i, i = 1, NTHREADS) ]
type(c_pthread_t) :: threads(NTHREADS)
type(c_ptr) :: ptr
print '("Starting threads ...")'
! Create threads.
do i = 1, NTHREADS
rc = c_pthread_create(threads(i), c_null_ptr, c_funloc(hello), c_loc(routines(i)))
end do
print '("Waiting for threads to finish ...")'
! Join threads.
do i = 1, NTHREADS
rc = c_pthread_join(threads(i), ptr)
end do
contains
recursive subroutine hello(arg) bind(c)
!! Runs inside a thread and prints out current thread id and loop
!! iteration.
type(c_ptr), intent(in), value :: arg !! Client data as C pointer.
integer, pointer :: n ! Fortran pointer to client data.
integer :: i, rc
if (.not. c_associated(arg)) return ! Check whether argument has been passed.
call c_f_pointer(arg, n) ! Convert C pointer to Fortran pointer.
do i = 1, 5
print '("--- Thread #", i0, " - Loop iteration ", i0)', n, i
rc = c_usleep(10**6) ! Sleep 1 sec.
end do
end subroutine hello
end program main
In Fortran 2003, the subroutine hello()
has to be delared inside
a module. Starting with Fortran 2008, program routines are allowed to have the
bind(c)
attribute as well. In Fortran 2018, the
recursive
attribute of subroutine hello()
is not
required anymore. Link the example against libfortran-unix.a
and
-lpthread
, and then run the binary:
$ gfortran13 -o example example.f90 libfortran-unix.a -lpthread
$ ./example
Starting threads ...
--- Thread #1 - Loop iteration 1
--- Thread #2 - Loop iteration 1
Waiting for threads to finish ...
--- Thread #3 - Loop iteration 1
--- Thread #1 - Loop iteration 2
--- Thread #2 - Loop iteration 2
--- Thread #3 - Loop iteration 2
--- Thread #1 - Loop iteration 3
--- Thread #3 - Loop iteration 3
--- Thread #2 - Loop iteration 3
--- Thread #1 - Loop iteration 4
--- Thread #3 - Loop iteration 4
--- Thread #2 - Loop iteration 4
--- Thread #1 - Loop iteration 5
--- Thread #3 - Loop iteration 5
--- Thread #2 - Loop iteration 5
Fortran Libraries
- fortran-unix: Fortran 2008 interface bindings to POSIX threads
References
< OpenMP | [Index] | Fork > |