Process synchronization

  • Post author:
  • Post last modified:August 16, 2023
  • Reading time:4 mins read

1.0 Problem

Suppose there are n concurrent peer processes, where n > 1. All these processes have a checkpoint, which is an important point in the execution trace of the process. These processes need to be synchronized such that no process crosses its checkpoint before the others have reached their individual checkpoints. For example, a software system might have multiple processes and it might be desirable they all finish their initialization routines before transaction processing can begin.

Concurrent processes
Figure 1: Concurrent Processes P0 – P4. Each process Pn has a checkpoint at time tn. No process should proceed beyond checkpoint until all processes have reached their individual checkpoints.

2.0 Solution

The problem is easily solved using counting semaphores. Suppose there are n processes, where n > 1. There is a semaphore for each process with initial value 0. Once a process reaches a checkpoint it does a V operation on its semaphore (n – 1) times. That is, the value of its semaphore becomes (n – 1). Then, it does a P operation on semaphores of other (n – 1) processes. When this completes, all processes have passed their respective checkpoints and have been synchronized.

3.0 Example Program

We have an example program that demonstrates the above solution for three processes. The same program is run as three processes, viz., Process 0, Process 1 and Process 2. Each process does some work and reaches its checkpoint. It, then, synchronizes with other processes. After synchronization, the processes do some arbitrary work.

/*
 *
 *   process.c: program to demonstrate process synchronization
 *         
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
#include <unistd.h>
#include <time.h>

#define NUM_PROCESSES 3
#define MAX_SLEEP_TIME 5     // seconds
#define PRIME_MOD 937

sem_t *sem [NUM_PROCESSES];
char buf [128];

int main (int argc, char **argv)
{
    int i, my_process_id;

    if (argc != 2) {
	fprintf (stderr, "Usage: process-id\n");
	exit (EXIT_FAILURE);
    }
    sscanf (argv [1], "%d", &my_process_id);
    
    fprintf (stderr, "(%d): Hello, World!\n", my_process_id);
    if (my_process_id < 0 || my_process_id >= NUM_PROCESSES) {
        fprintf (stderr, "process id = %d. Out of range\n", my_process_id);
	exit (EXIT_FAILURE);
    }

    // create/open semaphores
    for (i = 0; i < NUM_PROCESSES; i++) {
	sprintf (buf, "/sem-%d", i);
        if ((sem [i] = sem_open (buf, O_CREAT, 0660, 0)) == SEM_FAILED) {
            perror ("sem_open"); exit (EXIT_FAILURE);
        }
    } 

    time_t now = time (NULL);
    srand ((unsigned int) (now % PRIME_MOD));

    unsigned int sleep_time;
    // sleep for random time
    sleep_time = rand () % MAX_SLEEP_TIME;
    (void) sleep (sleep_time);

    // checkpoint; synchronize
    fprintf (stderr, "(%d): Checkpoint, synchronizing ...\n", my_process_id);
    //V (sem-id); (n - 1) times
    for (i = 0; i < (NUM_PROCESSES - 1); i++) {
        if (sem_post (sem [my_process_id]) == -1) {
            perror ("sem_post"); exit (EXIT_FAILURE);
        }
    }

    for (i = 0; i < NUM_PROCESSES; i++) {
        if (i != my_process_id) {
	    // P (sem-id)
	    if (sem_wait (sem [i]) == -1) {
	        perror ("sem_wait"); exit (EXIT_FAILURE);
            }
	}
    }

    fprintf (stderr, "(%d): synchronized. Will do rest of the work.\n", my_process_id);
    
    // sleep for random time
    sleep_time = rand () % MAX_SLEEP_TIME;
    (void) sleep (sleep_time);

    // Remove semaphore
    sprintf (buf, "/sem-%d", my_process_id);
    if (sem_unlink (buf) == -1) {
        perror ("sem_unlink"); exit (EXIT_FAILURE);
    }
    
    fprintf (stderr, "(%d): Bye.\n", my_process_id);
    exit (0);
}

We can compile the above program and run it as three processes, as below.

$ ./process 0 & ./process 1 & ./process 2 & ps
[1] 19907
[2] 19908
[3] 19909
(1): Hello, World!
(0): Hello, World!
(2): Hello, World!
    PID TTY          TIME CMD
  19374 pts/2    00:00:00 bash
  19907 pts/2    00:00:00 process
  19908 pts/2    00:00:00 process
  19909 pts/2    00:00:00 process
  19910 pts/2    00:00:00 ps
$ (0): Checkpoint, synchronizing ...
(1): Checkpoint, synchronizing ...
(2): Checkpoint, synchronizing ...
(2): synchronized. Will do rest of the work.
(0): synchronized. Will do rest of the work.
(1): synchronized. Will do rest of the work.
(0): Bye.
(2): Bye.
(1): Bye.

[1]   Done                    ./process 0
[2]-  Done                    ./process 1
[3]+  Done                    ./process 2
$ 

4.0 See also

POSIX Semaphores In Linux

Share

Karunesh Johri

Software developer, working with C and Linux.
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments