| Current Path : /var/www/html/bibhas.ghoshal/lab_files/ |
| Current File : /var/www/html/bibhas.ghoshal/lab_files/sem.c |
/* SEMAPHORES
Semaphores are system variables used for process synchronization. You may
think of a semaphore, s, as a variable maintained by the system. A semaphore
can be obtained by a semget() system call. Its initial value can be set by
the semctl() system call. There are two common operations that a process
can perform on a semaphore, s, namely:
P(s) or wait(s) : If the value of s is greater than 0, then
this operation decrements the value of s and
the calling process continues. Otherwise, if
s is 0, then the calling process is blocked on s.
V(s) or signal(s) : If any process is blocked on s, then this
unblocks (wakes up) the earliest among the
processes blocked on s. Otherwise, the value
of the semaphore is incremented.
In UNIX/Linux, both P(s) and V(s) can be done with the semop() system call
with appropriate parameters.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h> /* Include this to use semaphores */
/* We will define the P(s) and V(s) operations in terms of the semop()
system call. The syntax of semop is as follows:
int semop ( int semid, struct sembuf *sops, unsigned nsops)
where semid is the semaphore identifier returned by the semget()
system call. The second parameter is a pointer to a structure whichs
we must pass. The fields of this structure indicates whether we wish
to perform a P(s) operation or a V(s) operation. Refer to the system
manual for the third parameter -- we will always use 1 for this
parameter.
*/
#define P(s) semop(s, &pop, 1) /* pop is the structure we pass for doing
the P(s) operation */
#define V(s) semop(s, &vop, 1) /* vop is the structure we pass for doing
the V(s) operation */
main()
{
int *a, *b;
int i,j, count = 50, status;
int semid1, semid2 ;
struct sembuf pop, vop ;
/* In the following system calls, the second parameter indicates the
number of semaphores under this semid. Throughout this lab,
give this parameter as 1. If we require more semaphores, we
will take them under different semids through separate semget()
calls.
*/
semid1 = semget(IPC_PRIVATE, 1, 0777|IPC_CREAT);
semid2 = semget(IPC_PRIVATE, 1, 0777|IPC_CREAT);
/* The following system calls sets the values of the semaphores
semid1 and semid2 to 0 and 1 respectively. */
semctl(semid1, 0, SETVAL, 0);
semctl(semid2, 0, SETVAL, 1);
/* We now initialize the sembufs pop and vop so that pop is used
for P(semid) and vop is used for V(semid). For the fields
sem_num and sem_flg refer to the system manual. The third
field, namely sem_op indicates the value which should be added
to the semaphore when the semop() system call is made. Going
by the semantics of the P and V operations, we see that
pop.sem_op should be -1 and vop.sem_op should be 1.
*/
pop.sem_num = vop.sem_num = 0;
pop.sem_flg = vop.sem_flg = 0;
pop.sem_op = -1 ; vop.sem_op = 1 ;
/* We now illustrate a producer-consumer situation. The parent process
acts as the producer and the child process acts as the consumer.
Initially semid1 is zero, hence the consumer blocks. Since
semid2 is one, the producer produces (in this case writes some
values into the file). After this it wakes up the
consumer through the V(semid1) call. The consumer reads the
value and in turn performs V(semid2) to wake up the producer.
Trace through the code and work out the values of the two
semaphores and see how they synchronize the producer and the
consumer to wait for each other.
*/
if (fork() == 0) {
/* Child Process:: Consumer */
FILE *fp;
int data;
while (count) {
P(semid1);
fp = fopen("datafile","r");
fscanf(fp, "%d", &data);
printf("\t\t\t\t Consumer reads %d\n",data);
fclose(fp);
V(semid2);
count--;
}
}
else {
/* Parent Process:: Producer */
FILE *fp;
int data = 0;
while (count) {
sleep(1);
P(semid2);
fp = fopen("datafile","w");
fprintf(fp, "%d\n", data);
printf("Producer writes %d\n", data);
data++;
fclose(fp);
V(semid1);
count--;
}
wait(&status);
/* Semaphores need to be
deleted after they are used. In this case also,
exactly one process should delete it after making
sure that noone else is using it.
*/
semctl(semid1, 0, IPC_RMID, 0);
semctl(semid2, 0, IPC_RMID, 0);
}
}