IPC Using Semaphores in C – Types & System Calls

Inter process communication – semaphores

INTRODUCTION

In modern operating systems, processes often need to communicate and coordinate with each other, especially when they share resources such as memory, files, or hardware devices. This coordination, known as inter process communication (IPC), is essential to ensure efficient and error-free execution. Without proper synchronization, multiple processes accessing the same resource can lead to race conditions, data corruption, and system instability.

In C programming, particularly in UNIX/Linux environments, System V semaphores are commonly used. They are implemented through system calls such as semget() for creating or accessing a semaphore set, semop() for performing operations like wait (P) and signal (V), and semctl() for controlling or configuring semaphores. These system calls allow precise control over process synchronization and resource management. You can read more about these system calls in the GNU C Library Semaphore documentation.

Understanding how semaphores work is crucial for developers working in systems programming, embedded systems, and multithreaded applications. For more context, you can also refer to our guide on Inter Process Communication in Embedded Systems to see how these concepts apply in real-world projects. In the sections that follow, we will explore the concept of semaphores in detail, along with code examples and practical use cases that demonstrate their role in effective inter process communication.

Why Do We Need Semaphores?

  • Purpose: To protect critical (common) sections of code shared among multiple processes.
  • When multiple processes try to access a shared resource simultaneously, it leads to conflicts or data corruption.
  • Example:
  • If 3 users send print jobs to 1 printer at the same time, outputs may overlap.
  • Using semaphores, the printer is locked by one process at a time, ensuring orderly execution.

Types of Semaphores

1. Binary Semaphore

  • Has only two values: 0and 1 (i.e., locked/unlocked).
  • Works like a mutex (mutual exclusion).
  • Used when only one process is allowed in the critical section at a time.

2. Counting Semaphore

  • Can have values more than 1(resource count).
  • Used to manage multiple identical resources.
  • Allows multiple processes up to the count of available resources.

Example: Counting Semaphore

  • Assume 5 printers are available.
  • 3 print jobs arrive → 3 printers used.
  • 4 more jobs come:
  • 2 printers are still available → 2 jobs assigned.
  • Remaining 2 jobs wait until any printer becomes free.
  • Counting semaphores help in scheduling jobs based on available resource count.

Key Points

  • Semaphore = Lock mechanism for resource control.
  • Prevents race conditions in critical sections.
  • Helps in process synchronization.
  • Used in multithreading and multitasking

To perform synchronization using semaphores, following are the steps −

Step 1 − Create a semaphore or connect to an already existing semaphore using semget().

Step 2 − Perform operations on the semaphore, i.e., allocate, release, or wait for the resource using semop().

Step 3 − Perform control operations on the semaphore like initializing, removing, or getting values using semctl().

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg)

This system call creates or allocates a System V semaphore set. The following arguments need to be passed –

  1. The first argument, key −
    Recognizes the semaphore set. It can be either an arbitrary value or derived from the ftok() library function.
  2. The second argument, nsems −
    Specifies the number of semaphores.
  • If binary, then it is 1, meaning 1 semaphore set is needed.
  • Otherwise, set as per the required countof semaphore sets.
  1. The third argument, semflg −
    Specifies the required semaphore flags, such as:
  • IPC_CREAT: Creates the semaphore if it does not exist.
  • IPC_EXCL: Used with IPC_CREAT; the call fails if a semaphore already exists.
    Also includes permission bits(e.g., 0666).

Note − Refer earlier sections for details on permissions.

 On success −
Returns a valid semaphore identifier (used in further semaphore operations).

 On failure −
Returns -1.
To identify the error, use the errno variable or the perror() function.

 Common errors −

  • EACCES− Permission denied.
  • EEXIST− Semaphore set already exists and cannot be created.
  • ENOENT− Semaphore set does not exist.
  • ENOMEM− Not enough memory to create the semaphore set.
  • ENOSPC− Maximum limit of semaphore sets has been reached.

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

This system call performs the operations on the System V semaphore sets viz., allocating resources, waiting for the resources or freeing the resources. Following arguments need to be passed –

  1. The first argument, semid −
    Indicates the semaphore set identifiercreated by the semget()function.
  2. The second argument, semops −
    Is the pointer to an arrayof operations to be performed on the semaphore set.
    The structure used is:

struct sembuf 

unsigned short sem_num;/* Semaphore set num */

short sem_op;/* Semaphore operation */

short sem_flg;/* Operation flags, IPC_NOWAIT, SEM_UNDO */

};

Element, sem_op, in the above structure, indicates the operation that needs to be performed –

 If sem_op is negative (−ve) −
Allocate or obtain resources.
Blocks the calling process until enough resources are released by other processes.

 If sem_op is zero −
The calling process waits until the semaphore value becomes 0.

 If sem_op is positive (+ve) −
Release resources (i.e., increment the semaphore value).

For example –

struct sembuf sem_lock = { 0, -1, SEM_UNDO };

struct sembuf sem_unlock = {0, 1, SEM_UNDO };

  • The third argument, nsemops −
    Specifies the number of operationsin the semops 

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/sem.h>

int semctl(int semid, int semnum,int cmd,) 

This system call performs control operation for a System V semaphore. The following arguments need to be passed – 

  1. The first argument, semid −
    Is the semaphore identifier, which is the return value of the semget()system call.
  2. The second argument, semnum −
    Is the number of the semaphore. Semaphores are numbered starting from 0.
  3. The third argument, cmd −
    Specifies the commandto perform the required control operation on the semaphore.
  4. The fourth argument, of type union semun
    Depends on the cmdvalue.
    • For some commands, this argument is not applicable.

Let us check the union semun – 

 

union semun

{

int val;/* val for SETVAL */

struct semid_ds *buf; /* Buffer for IPC_STAT and IPC_SET */ 

unsigned short *array; /* Buffer for GETALL and SETALL */ 

struct seminfo *__buf; /* Buffer for IPC_INFO and SEM_INFO*/ 

};

The semid_ds data structure which is defined in sys/sem.h is as follows –

 

struct semid_ds 

struct ipc_perm sem_perm; /* Permissions */ 

time_t sem_otime; /* Last semop time */ 

time_t sem_ctime; /* Last change time */ 

unsigned long sem_nsems; /* Number of semaphores in the set */

 };

Note − Please refer to the manual pages for other data structures.

union semun arg;
Valid values for cmd are −

  • IPC_STAT
    Copies the current values of each member of the struct semid_ds to the structure pointed to by buf.
    This command requires read permission for the semaphore.
  • IPC_SET
    Sets the user ID, group ID of the owner, permissions, etc., as pointed to by the struct semid_ds.
  • IPC_RMID
    Removes the semaphore set.
  • IPC_INFO
    Returns information about the semaphore limits and parameters in the struct semid_ds pointed to by __buf.
  • SEM_INFO
    Returns a seminfo structure containing information about the system resources consumed by the semaphore.
  • Create two processes: Parent and child.
  • Shared Memory: Used to store a counter and flags for read/write status.
  • Increment Counter: Both parent and child increment the counter in parallel. The count is passed via a command-line argument or defaults to a value if not specified.
  • Issue: Parallel access to the shared memory causes incorrect counter increment, as the final value should be double the counter.
  • Solution: Use a semaphore (c) to ensure one process completes before the other starts.
  • Shared Memory Read: The value is checked in c after completion.
  • Execution: Run the write program in one terminal and the read program in another. The write program waits until the read program finishes before completing.

New IoT Internship with Project Batch Starts on 19th May!
Seats are filling fast — don’t miss your chance to join!

✅ Work on real-time IoT projects
✅ Gain hands-on experience

📞 For more details & registration, contact us now!

Contact no:9886920008

Limited seats available — Hurry!