Search code examples
clinuxmultithreadingoperating-system

Synchronising processes in C, linux


The problem is more difficult, but I want to understand an easier example. Let's say I have 3 processes, and I want process 3 to start before process 1, how can I do it? Or, is it possible to do it?

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <semaphore.h>

int main() {
    sem_t semaphore;

    // Initialize semaphore with initial value 0
    if (sem_init(&semaphore, 0, 0) == -1) {
        perror("Semaphore initialization failed");
        exit(EXIT_FAILURE);
    }

    // Create child process 1
    if (fork() == 0) {
        // Child process 1 (Process 1) starts here
        printf("Process 1 started.\n");
        // Wait for signal from Process 3
        sem_wait(&semaphore); 
        printf("Process 1 completed its work.\n");
        exit(0);
    }

    // Create child process 2
    if (fork() == 0) {
        // Child process 2 (Process 2) starts here
        printf("Process 2 started.\n");
        printf("Process 2 completed its work.\n");
        exit(0);
    }

    // Create child process 3
    if (fork() == 0) {
        // Child process 3 (Process 3) starts here
        printf("Process 3 started.\n");
        // Signal Process 1 to start
        sem_post(&semaphore);
        exit(0);
    }

    wait(NULL);
    wait(NULL);
    wait(NULL);

    // Destroy semaphore
    sem_destroy(&semaphore);

    return 0;
}

This is the output I get:

Process 1 started.
Process 3 started.
Process 2 started.
Process 2 completed its work.

It's like running into an infinite loop, process 1 and process 3 do not terminate.


Solution

  • You need to use a "shared" semaphore to share/signal between processes. An unshared semaphore (like you're using) can only synchronize threads in a single process.

    To create a shared semaphore, you need to allocate it in shared memory, which is a bit tricky. The easiest way is to use

    #include <sys/mman.h>
    
        :
    
        sem_t *semaphore = mmap(0, sizeof(sem_t), PROT_READ|PROT_WRITE,
                                MAP_SHARED|MAP_ANONYMOUS, -1, 0);
        if (semaphore == MAP_FAILED || sem_init(semaphore, 1, 0) == -1) {
            perror("Semaphore initialization failed");
            exit(EXIT_FAILURE);
        }
    

    This is a bit ineffiecent as it allocates a whole page (usually 4096 bytes) for the semaphore, wasting most of it (mmap will round up the requested size to a multiple of the page size).

    If you need multiple semaphores, you can allocate them as an array with a single call to mmap. If you need more shared memory (such as buffers to communicate between the processes), you can gather all the things you need together into a single large struct and allocate that with mmap