Closing Channels in Fortran

program closing_channels
    use, intrinsic :: iso_fortran_env, only: int32, real32
    use omp_lib
    implicit none
    
    integer(int32) :: jobs(5)
    logical :: done
    integer(int32) :: i, status
    
    ! In this example we'll use a `jobs` array to communicate work to be done 
    ! from the main program to a worker thread. When we have no more jobs for
    ! the worker we'll set the `done` flag.

    ! Initialize the jobs array and done flag
    jobs = 0
    done = .false.

    ! Start the worker thread
    !$omp parallel sections
    !$omp section
        call worker(jobs, done)
    !$omp section
        ! This sends 3 jobs to the worker over the `jobs` array, then sets the done flag.
        do i = 1, 3
            jobs(i) = i
            print *, "sent job", i
        end do
        print *, "sent all jobs"
        done = .true.
    !$omp end parallel sections

    ! We await the worker using a simple busy-wait
    do while (.not. all(jobs == 0))
        call sleep(1)
    end do

    print *, "All jobs processed"

contains

    subroutine worker(jobs, done)
        integer(int32), intent(inout) :: jobs(:)
        logical, intent(in) :: done
        integer(int32) :: j
        
        ! Here's the worker subroutine. It repeatedly checks the jobs array
        ! for non-zero values. When it finds one, it processes the job and
        ! sets the array element back to zero. It continues until the done
        ! flag is set and all jobs have been processed.
        
        do while (.not. done .or. any(jobs /= 0))
            do j = 1, size(jobs)
                if (jobs(j) /= 0) then
                    print *, "received job", jobs(j)
                    jobs(j) = 0
                end if
            end do
            if (done .and. all(jobs == 0)) then
                print *, "received all jobs"
                return
            end if
        end do
    end subroutine worker

end program closing_channels

This Fortran program demonstrates a concept similar to closing channels in concurrent programming. Here’s a breakdown of the code:

  1. We define a main program that uses OpenMP for parallel execution.

  2. Instead of channels, we use a shared array jobs to communicate work between the main thread and the worker thread.

  3. The worker subroutine runs in a separate thread and continuously processes jobs from the jobs array until the done flag is set and all jobs are completed.

  4. The main thread sends jobs by setting values in the jobs array and then sets the done flag when all jobs have been sent.

  5. After sending all jobs, the main thread waits for the worker to complete all jobs using a simple busy-wait loop.

To compile and run this Fortran program:

$ gfortran -fopenmp closing_channels.f90 -o closing_channels
$ ./closing_channels
sent job 1
sent job 2
sent job 3
sent all jobs
received job 1
received job 2
received job 3
received all jobs
All jobs processed

Note that the exact output order may vary due to the concurrent nature of the program.

This example demonstrates how to implement a concept similar to closing channels in Fortran using shared memory and OpenMP for concurrent execution. While Fortran doesn’t have built-in channel primitives like some modern languages, we can achieve similar functionality using arrays and flags for inter-thread communication.