Inter-Process Communication

Modern POSIX-compliant operating systems provide several means of inter-process communication (IPC), among others:

Signals

On POSIX-compliant operating systems, signals are used to interrupt, terminate, or control running processes. A process can react to specific signals by implementing signal handlers. For example, an application may catch SIGINT to terminate when the user presses CTRL + C. Some signal numbers for FreeBSD are shown in table 1. See the man pages for a list of all signals. The GNU Fortran provides a compiler-dependent interface to POSIX signals.

No. Name Default Action Description
1 SIGHUP Terminate process. Terminal line hang-up.
2 SIGINT Terminate process. Interrupt program.
3 SIGQUIT Create core image. Quit program.
9 SIGKILL Terminate process. Kill program.
Table 1: Selection of signals on FreeBSD (source)

A signal handler is registered by calling the signal() routine. The signal number and the handler function must be passed as arguments:

! signal.f90
program main
    external :: sigint_handler

    call signal(2, sigint_handler)
    call sleep(30)
end program main

subroutine sigint_handler()
    print '(a)', 'Process interrupted (SIGINT), exiting ...'
end subroutine sigint_handler

Press CTRL + C to send SIGINT to the Fortran program. The signal handler must be an external routine, hence without access to any variables or subroutines of the inner program.

Anonymous Pipes

Unix pipes allow processes to communicate with other processes without having been designed explicitly for this task. The input and output streams of processes can be chained together, providing a one-way flow of data.

Anonymous or unnamed pipes are a way of inter-process communication that let the output of one program to become the input of another. The output can be redirected by using the pipe symbol | on the command-line.

The following example program reads given values in degrees Fahrenheit (°F) from stdin and writes the converted values in degrees Celsius (°C) to stdout:

! f2c.f90
program f2c
    implicit none
    integer :: rc
    real    :: f

    do
        read (*, *, iostat=rc) f                ! Read degrees Fahrenheit (without unit) from stdin.
        if (rc /= 0) exit                       ! Exit on input error.
        print '(f0.2, " °C")', (f - 32) * 5 / 9 ! Write degrees Celsius (with unit) to stdout.
    end do
end program f2c

After compilation, just pipe the value in degrees Fahrenheit to the Fortran program:

$ gfortran9 -o f2c f2c.f90
$ echo "60.45" | ./f2c
15.81 °C

The < symbol allows to redirect the input to come from a file, while > writes the output to a file:

$ cat fahrenheit.txt
24.6
74.3
79.8
30.0
$ ./f2c < fahrenheit.txt
-4.11 °C
23.50 °C
26.56 °C
-1.11 °C

Read the input values from file fahrenheit.txt and write the output to file celsius.txt:

$ ./f2c < fahrenheit.txt > celsius.txt
$ cat celsius.txt
-4.11 °C
23.50 °C
26.56 °C
-1.11 °C

The output of a Fortran program can be piped to other applications as well, for instance, to format the current time:

! time.f90
program time
    implicit none
    integer :: dt(8)

    call date_and_time(values=dt)
    print '(3(i0, a), i0)', dt(5), ":", dt(6), ":", dt(7), ":", dt(8)
end program time

Pipe the output of time to figlet:

$ gfortran9 -o time time.f90
$ ./time | figlet -f mini
        _  _  _  _     _ __
/||_|_o|_ / \o_)|_ o/||_  /
 |  | o _)\_/o_) _)o ||_)/

Named Pipes

A further kind of pipes are named pipes, also knows as FIFO (“first in, first out”). The pipe name is simply an arbitrary file name within the file system. On Unix, named pipes can be created with mkfifo, and removed with rm or unlink.

$ mkfifo ./pipe
$ echo "Hello, World!" > ./pipe

Another process can then read from the named pipe:

$ tail -f ./pipe
Hello, World!