Process Synchronization Using Semaphores (Simple Ordering Example)

 

1. AIM

To implement a simple process synchronization mechanism using semaphores, ensuring that Process P1 executes before Process P2.


2. OBJECTIVE

  • To understand the concept of semaphores for process synchronization.

  • To control the order of execution between concurrent processes.

  • To demonstrate the use of wait() and signal() semaphore operations.


3. THEORY

Process Synchronization

When multiple processes run concurrently, they may require controlled access to shared resources or need coordinated execution.

Semaphores

A semaphore is a special synchronization variable used to solve coordination and mutual exclusion problems.
There are two primary operations:

  • wait(S) – decreases semaphore value; if it becomes negative, the process waits.

  • signal(S) – increases semaphore value; if processes are waiting, one is awakened.

Problem Description

We have two processes:

  1. P1 – must run first

  2. P2 – must run only after P1 finishes

We use a semaphore initialized to 0, which makes P2 wait until P1 signals it.

This is a simple example of execution ordering using semaphores.


4. ALGORITHM

Initialization

Initialize semaphore S = 0

Process P1

Print "P1: Task started" Print "P1: Task finished" signal(S) // Allow P2 to continue

Process P2

wait(S) // Wait until P1 completes Print "P2: Task started" Print "P2: Task finished"

5. PROGRAM (C using POSIX Threads & Semaphores)

#include <stdio.h> #include <pthread.h> #include <semaphore.h> sem_t sem; // Semaphore void* process1(void* arg) { printf("P1: Task started\n"); printf("P1: Task finished\n"); sem_post(&sem); // Signal P2 to proceed return NULL; } void* process2(void* arg) { sem_wait(&sem); // Wait for P1 to signal printf("P2: Task started\n"); printf("P2: Task finished\n"); return NULL; } int main() { pthread_t t1, t2; sem_init(&sem, 0, 0); // Initialize semaphore to 0 pthread_create(&t1, NULL, process1, NULL); pthread_create(&t2, NULL, process2, NULL); pthread_join(t1, NULL); pthread_join(t2, NULL); sem_destroy(&sem); return 0; }

6. SAMPLE OUTPUT

P1: Task started P1: Task finished P2: Task started P2: Task finished

Explanation

Although both threads run concurrently:

  • P2 waits at sem_wait()

  • P1 prints first, then signals using sem_post()

  • P2 then runs, ensuring correct execution order

This demonstrates simple synchronization using semaphores.


7. RESULT

The program successfully demonstrates the use of semaphores to enforce execution ordering between two processes, ensuring that P1 always executes before P2.


Explanation of Functions Used in the Program

The program uses POSIX threads and POSIX semaphores.
Here is what each function does:


1. pthread_create()

Prototype

int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);

Purpose

Creates a new thread and starts executing the function passed to it.

Where used

pthread_create(&t1, NULL, process1, NULL); pthread_create(&t2, NULL, process2, NULL);

Meaning

  • &t1 / &t2 → variables to store thread IDs

  • NULL → default thread attributes

  • process1 / process2 → functions executed by the threads

  • NULL → no arguments passed


2. pthread_join()

Prototype

int pthread_join(pthread_t thread, void **retval);

Purpose

Makes the main thread wait until the created thread finishes.

Where used

pthread_join(t1, NULL); pthread_join(t2, NULL);

Meaning

Main program waits until t1 and t2 threads complete.


3. sem_init()

Prototype

int sem_init(sem_t *sem, int pshared, unsigned int value);

Purpose

Initializes a semaphore with a starting value.

Where used

sem_init(&sem, 0, 0);

Meaning

  • &sem → semaphore variable

  • 0 → semaphore is shared among threads in the same process

  • 0 → initial value; causes sem_wait to block

This ensures P2 waits for P1.


4. sem_wait()

Prototype

int sem_wait(sem_t *sem);

Purpose

Performs the wait (P operation) on a semaphore.

Behavior

  • Decrements the value of the semaphore.

  • If value becomes negative, the calling thread blocks (waits).

Where used

sem_wait(&sem);

Meaning

P2 waits here until P1 calls sem_post().


5. sem_post()

Prototype

int sem_post(sem_t *sem);

Purpose

Performs the signal (V operation).

Behavior

  • Increments the semaphore value.

  • If any thread was waiting, one gets unblocked.

Where used

sem_post(&sem);

Meaning

P1 signals P2 that it may proceed.


6. sem_destroy()

Prototype

int sem_destroy(sem_t *sem);

Purpose

Releases resources associated with a semaphore.

Where used

sem_destroy(&sem);

Meaning

Cleans up memory once the program is done.


7. Thread Functions (process1 and process2)

Prototype

void* process1(void* arg); void* process2(void* arg);

Purpose

These functions are executed inside threads.

What they do

  • process1() prints messages and signals the semaphore.

  • process2() waits for the signal and then prints its messages.

Summary Table

FunctionPurpose
pthread_create()                        Creates new threads
pthread_join()                        Waits for threads to finish
sem_init()                        Initializes semaphore
sem_wait()                        Waits until semaphore > 0
sem_post()                        Signals the semaphore (unblocks waiting thread)
sem_destroy()                        Destroys semaphore

Comments

Popular posts from this blog

Operating Systems OS Lab PCCSL407 Semester 4 KTU BTech CS 2024 Scheme - Dr Binu V P

Exploring the /proc file system

ps command