Skip to content

Inter-process communication and shared memory

Processes within a system can be independent or decide to cooperate. For cooperation, it’s important that the OS provides efficient means of communication between them.

Shared memory, as the name implies, is an area in the system memory that two programs can access.

The communication is under control of the processes, who have to manage synchronization between memory accesses.

Example: producer, using POSIX API:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mman.h>
#include <sys/shm.h>
#include <sys/stat.h>

int main() {
    const int SIZE = 4096; // Size of the shared memory object.
    const char* NAME = "SM"; // Name of the shared memory object.
    const char* message_0 = "Hello ";
    const char* message_1 = "World!";


    // Shared memory file descriptor.
    int shm_fd = shm_open(NAME, O_CREAT | O_RDWR, 0666);
    ftruncate(shm_fd, SIZE);

    // Pointer to shared memory object.
    void* ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);

    // sprintf writes formatted output to the ptr string.
    sprintf(ptr, "%s", message_0);
    ptr += strlen(message_0);
    sprintf(ptr, "%s", message_1);
    ptr += strlen(message_1);

    return 0;
}

Example: consumer, using POSIX API:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/shm.h>

int main() {
    const int SIZE = 4096;
    const char* NAME = "SM";

    int shm_fd = shm_open(NAME, O_RDONLY, 0666);
    void* ptr = mmap(NULL, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);

    // Print the contents of the shared memory (until it finds the first 0 byte).
    printf("%s", (char*)ptr);

    // Remove the shared memory object.
    shm_unlink(NAME);

    return 0;
}

Message passing is a simple method of communication.

Usually the API is composed of at least 2 functions

  • send(message);
  • receive();

The two processes that want to communicate have to set up a channel where messages of fixed or variable length are passed.

Ordinary pipes (or anonymous pipes) are a form of channel that cannot be accessed outside of the process that created it.

Typically a parent creates the pipe and uses it to communicate with a child process that it created.

They allow unidirectional communication between the producer and the consumer of the messages.

Named pipes can be accessed without a parent-child relationship.

They provide bidirectional and multi-process communication.