Ex05-Linux IPC-Semaphores
To Write a C program that implements a producer-consumer system with two processes using Semaphores.
Navigate to any Linux environment installed on the system or installed inside a virtual environment like virtual box/vmware or online linux JSLinux (https://bellard.org/jslinux/vm.html?url=alpine-x86.cfg&mem=192) or docker.
Write the C Program using Linux Process API - Sempahores
Execute the C Program for the desired output.
/*
* sem.c - demonstrates a basic producer-consumer
* implementation. */
#include <stdio.h> /* standard I/O routines. */
#include <stdlib.h> /* rand() and srand() functions */
#include <unistd.h> /* fork(), etc. */
#include <time.h> /* nanosleep(), etc. */
#include <sys/types.h> /* various type definitions. */
#include <sys/ipc.h> /* general SysV IPC structures */
#include <sys/sem.h> /* semaphore functions and structs. */
#define NUM_LOOPS 20 /* number of loops to perform. */
#if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
/* union semun is defined by including <sys/sem.h> */
#else
/* according to X/OPEN we have to define it ourselves */
union semun {
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
unsigned short int *array; /* array for GETALL, SETALL */
struct seminfo *__buf; /* buffer for IPC_INFO */
};
#endif
int main(int argc, char* argv[])
{
int sem_set_id; /* ID of the semaphore set. */
union semun sem_val; /* semaphore value, for semctl(). */
int child_pid; /* PID of our child process. */
int i; /* counter for loop operation. */
struct sembuf sem_op; /* structure for semaphore ops. */
int rc; /* return value of system calls. */
struct timespec delay; /* used for wasting time. */
/* create a private semaphore set with one semaphore in it, */
/* with access only to the owner. */
sem_set_id = semget(IPC_PRIVATE, 1, 0600);
if (sem_set_id == -1) {
perror("main: semget");
exit(1);
}
printf("semaphore set created, semaphore set id '%d'.\n", sem_set_id);
/* intialize the first (and single) semaphore in our set to '0'. */
sem_val.val = 0;
rc = semctl(sem_set_id, 0, SETVAL, sem_val);
/* fork-off a child process, and start a producer/consumer job. */
child_pid = fork();
switch (child_pid) {
case -1: /* fork() failed */
perror("fork");
exit(1);
case 0: /* child process here */
for (i=0; i<NUM_LOOPS; i++) {
/* block on the semaphore, unless it's value is non-negative. */
sem_op.sem_num = 0;
sem_op.sem_op = -1;
sem_op.sem_flg = 0;
semop(sem_set_id, &sem_op, 1);
printf("consumer: '%d'\n", i);
fflush(stdout);
}
break;
default: /* parent process here */
for (i=0; i<NUM_LOOPS; i++) {
printf("producer: '%d'\n", i);
fflush(stdout);
/* increase the value of the semaphore by 1. */
sem_op.sem_num = 0;
sem_op.sem_op = 1;
sem_op.sem_flg = 0;
semop(sem_set_id, &sem_op, 1);
/* pause execution for a little bit, to allow the */
/* child process to run and handle some requests. */
/* this is done about 25% of the time. */
if (rand() > 3*(RAND_MAX/4)) {
delay.tv_sec = 0;
delay.tv_nsec = 10;
//nanosleep(&delay, NULL);
sleep(10);
}
if(NUM_LOOPS>=10) {
semctl(sem_set_id, 0, IPC_RMID, sem_val) ;
} // Remove the sem_set_id
}
}
return 0;
}
$ ./sem.o
$ ipcs
The program is executed successfully.