Skip to content

Lecture No. 08

Dated: 11-05-2025

Inter Process Communication

It provides a mechanism for processes to communicate and synchronize their actions without sharing the same address space.

Message Passing System

This allows processes to communicate without shared data. Messages sent by a process may be of either fixed or variable length.

There are several methods for logically implementing a link for the processes to communicate.

Direct Communication

Primitives

Send(P, message)

Sends a message to process P.

Receive(Q, message)

Receive a message from process Q.

Properties

  • Only 1 link can exist between exactly 2 processes.
  • Processes need to know each other's ID to be able to communicate.

Indirect Communication

Primitives

Send(A, message)

Send a message to mailbox A.

Receive(A, message)

Receive a message from mailbox A.

Properties

  • A link between multiple processes will only exist if they share the same mailbox.
  • Multiple links can exist but each will be associated with a certain mailbox.

Synchronization

Primitives

Blocking Send

The sending process is blocked until the message is received.

Non Blocking Send

The sending process sends the message and resumes operation.

Blocking Receive

The receiver blocks until a message is available.

Non Blocking Receiver

The receiver receives either a valid message or a null.

Buffering

Messages exchanged by the processes reside in a temporary queue.

Zero Capacity

  • Has zero length.
  • Message cannot wait.
  • Sender must block receiver.

Bounded Capacity

  • Has \(n\) size.
  • Sender blocks receiver until there is space in queue.

Unbounded Capacity

  • Has \(\infty\) size.
  • Sender never blocks receiver.

Unix / Linux IPC Tools

  • Pipe
  • Named pipe (FIFO)
  • BSD Socket
  • TLI
  • Message queue
  • Shared memory

read()

#include <unistd.h>
ssize_t read(int file_descriptor, void* buf, size_t count);

if count is

  • \(= 0\) then read() returns \(0\).
  • \(>\) SSIZE_MAX, the result is unspecified.

On success, read() returns number of bytes read and 0 indicates EOF.
It also advances the file position pointer.

write()

#include <unistd.h>
ssize_t write(int file_descriptor, const void* buf, size_t count);

close()

#include <unistd.h>
int close(int file_descriptor);

pipe()

#include <unistd.h>
int pipe(int file_descriptor[2]);
  1. For reading
  2. For writing

A pipe is bounded buffer and the maximum data which can be written, is PIPE_BUF.
Defined:

  • as \(5120\) in "sys/param.h"
  • as \(4096\) in "linux/param.h"

Example

/* Parent creates pipe, forks a child, child writes into
   pipe, and parent reads from pipe */
#include <stdio.h>
#include <stdlib.h>     // For exit()
#include <string.h>     // For strlen()
#include <unistd.h>     // For pipe(), fork(), read(), write(), close()
#include <sys/types.h>  // For pid_t
#include <sys/wait.h>   // For wait()

int main() {
    int pipefd[2], pid, n, rc, nr, status;
    char *testString = "Hello, world!\n";
    char buf[1024];

    rc = pipe(pipefd);
    if (rc < 0) {
        perror("pipe");
        exit(1);
    }

    pid = fork();
    if (pid < 0) {
        perror("fork");
        exit(1);
    }

    if (pid == 0) { /* Child’s Code */
        close(pipefd[0]); // Close read end
        write(pipefd[1], testString, strlen(testString));
        close(pipefd[1]);
        exit(0);
    }

    /* Parent’s Code */
    close(pipefd[1]); // Close write end
    n = strlen(testString);
    nr = read(pipefd[0], buf, n);
    rc = write(1, buf, nr);
    wait(&status);
    printf("Good work child!\n");
    return 0;
}