# Operating System | Peterson’s Algorithm (Using processes and shared memory)

Prerequisite – synchronization, Critical Section

Problem:The producer consumer problem (or bounded buffer problem) describes two processes, the producer and the consumer, which share a common, fixed-size buffer used as a queue. Producer produce an item and put it into buffer. If buffer is already full then producer will have to wait for an empty block in buffer. Consumer consume an item from buffer. If buffer is already empty then consumer will have to wait for an item in buffer. Implement Peterson’s Algorithm for the two processes using shared memory such that there is mutual exclusion between them. The solution should have free from synchronization problems.

Peterson’s algorithm –

```
// code for producer (j)

// to produce an item
flag[j] = true;

// but consumer (i) can consume an item
turn = i;

// if consumer is ready to consume an item
// and if its consumer's turn
while (flag[i] == true && turn == i)

{ // then producer will wait }

// otherwise producer will produce
// an item and put it into buffer (critical Section)

// Now, producer is out of critical section
flag[j] = false;
// end of code for producer

//--------------------------------------------------------
// code for consumer i

// to consume an item
flag[i] = true;

// but producer (j) can produce an item
turn = j;

// if producer is ready to produce an item
// and if its producer's turn
while (flag[j] == true && turn == j)

{ // then consumer will wait }

// otherwise consumer will consume
// an item from buffer (critical Section)

// Now, consumer is out of critical section
flag[i] = false;
// end of code for consumer
```

Explanation of Peterson’s algorithm –

Peterson’s Algorithm is used to synchronize two processes. It uses two variables, a bool array flag of size 2 and an int variable turn to accomplish it.
In the solution i represents the Consumer and j represents the Producer. Initially the flags are false. When a process wants to execute it’s critical section, it sets it’s flag to true and turn as the index of the other process. This means that the process wants to execute but it will allow the other process to run first. The process performs busy waiting until the other process has finished it’s own critical section.
After this the current process enters it’s critical section and adds or removes a random number from the shared buffer. After completing the critical section, it sets it’s own flag to false, indication it does not wish to execute anymore.

The program runs for a fixed amount of time before exiting. This time can be changed by changing value of the the macro RT.

```// C program to implement Peterson’s Algorithm
// for producer-consumer problem.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdbool.h>
#define _BSD_SOURCE
#include <sys/time.h>
#include <stdio.h>

#define BSIZE 8 // Buffer size
#define PWT 2 // Producer wait time limit
#define CWT 10 // Consumer wait time limit
#define RT 10 // Program run-time in seconds

int shmid1, shmid2, shmid3, shmid4;
key_t k1 = 5491, k2 = 5812, k3 = 4327, k4 = 3213;
bool* SHM1;
int* SHM2;
int* SHM3;

int myrand(int n) // Returns a random number between 1 and n
{
time_t t;
srand((unsigned)time(&t));
return (rand() % n + 1);
}

int main()
{
shmid1 = shmget(k1, sizeof(bool) * 2, IPC_CREAT | 0660); // flag
shmid2 = shmget(k2, sizeof(int) * 1, IPC_CREAT | 0660); // turn
shmid3 = shmget(k3, sizeof(int) * BSIZE, IPC_CREAT | 0660); // buffer
shmid4 = shmget(k4, sizeof(int) * 1, IPC_CREAT | 0660); // time stamp

if (shmid1 < 0 || shmid2 < 0 || shmid3 < 0 || shmid4 < 0) {
perror("Main shmget error: ");
exit(1);
}
SHM3 = (int*)shmat(shmid3, NULL, 0);
int ix = 0;
while (ix < BSIZE) // Initializing buffer
SHM3[ix++] = 0;

struct timeval t;
time_t t1, t2;
gettimeofday(&t, NULL);
t1 = t.tv_sec;

int* state = (int*)shmat(shmid4, NULL, 0);
*state = 1;
int wait_time;

int i = 0; // Consumer
int j = 1; // Producer

if (fork() == 0) // Producer code
{
SHM1 = (bool*)shmat(shmid1, NULL, 0);
SHM2 = (int*)shmat(shmid2, NULL, 0);
SHM3 = (int*)shmat(shmid3, NULL, 0);
if (SHM1 == (bool*)-1 || SHM2 == (int*)-1 || SHM3 == (int*)-1) {
perror("Producer shmat error: ");
exit(1);
}

bool* flag = SHM1;
int* turn = SHM2;
int* buf = SHM3;
int index = 0;

while (*state == 1) {
flag[j] = true;
*turn = i;
while (flag[i] == true && *turn == i)
;

// Critical Section Begin
index = 0;
while (index < BSIZE) {
if (buf[index] == 0) {
int tempo = myrand(BSIZE * 3);
printf("Job %d has been produced\n", tempo);
buf[index] = tempo;
break;
}
index++;
}
if (index == BSIZE)
printf("Buffer is full, nothing can be produced!!!\n");
printf("Buffer: ");
index = 0;
while (index < BSIZE)
printf("%d ", buf[index++]);
printf("\n");
// Critical Section End

flag[j] = false;
if (*state == 0)
break;
wait_time = myrand(PWT);
printf("Producer will wait for %d seconds\n\n", wait_time);
sleep(wait_time);
}
exit(0);
}

if (fork() == 0) // Consumer code
{
SHM1 = (bool*)shmat(shmid1, NULL, 0);
SHM2 = (int*)shmat(shmid2, NULL, 0);
SHM3 = (int*)shmat(shmid3, NULL, 0);
if (SHM1 == (bool*)-1 || SHM2 == (int*)-1 || SHM3 == (int*)-1) {
perror("Consumer shmat error:");
exit(1);
}

bool* flag = SHM1;
int* turn = SHM2;
int* buf = SHM3;
int index = 0;
flag[i] = false;
sleep(5);
while (*state == 1) {
flag[i] = true;
*turn = j;
while (flag[j] == true && *turn == j)
;

// Critical Section Begin
if (buf[0] != 0) {
printf("Job %d has been consumed\n", buf[0]);
buf[0] = 0;
index = 1;
while (index < BSIZE) // Shifting remaining jobs forward
{
buf[index - 1] = buf[index];
index++;
}
buf[index - 1] = 0;
} else
printf("Buffer is empty, nothing can be consumed!!!\n");
printf("Buffer: ");
index = 0;
while (index < BSIZE)
printf("%d ", buf[index++]);
printf("\n");
// Critical Section End

flag[i] = false;
if (*state == 0)
break;
wait_time = myrand(CWT);
printf("Consumer will sleep for %d seconds\n\n", wait_time);
sleep(wait_time);
}
exit(0);
}
// Parent process will now for RT seconds before causing child to terminate
while (1) {
gettimeofday(&t, NULL);
t2 = t.tv_sec;
if (t2 - t1 > RT) // Program will exit after RT seconds
{
*state = 0;
break;
}
}
// Waiting for both processes to exit
wait();
wait();
printf("The clock ran out.\n");
return 0;
}
```

Output:

```Producer is ready now.

Job 9 has been produced
Buffer: 9 0 0 0 0 0 0 0
Producer will wait for 1 seconds

Job 8 has been produced
Buffer: 9 8 0 0 0 0 0 0
Producer will wait for 2 seconds

Job 13 has been produced
Buffer: 9 8 13 0 0 0 0 0
Producer will wait for 1 seconds

Job 23 has been produced
Buffer: 9 8 13 23 0 0 0 0
Producer will wait for 1 seconds

Job 9 has been consumed
Buffer: 8 13 23 0 0 0 0 0
Consumer will sleep for 9 seconds

Job 15 has been produced
Buffer: 8 13 23 15 0 0 0 0
Producer will wait for 1 seconds

Job 13 has been produced
Buffer: 8 13 23 15 13 0 0 0
Producer will wait for 1 seconds

Job 11 has been produced
Buffer: 8 13 23 15 13 11 0 0
Producer will wait for 1 seconds

Job 22 has been produced
Buffer: 8 13 23 15 13 11 22 0
Producer will wait for 2 seconds

Job 23 has been produced
Buffer: 8 13 23 15 13 11 22 23
Producer will wait for 1 seconds

The clock ran out.
```

This article is contributed by Nabaneet Roy. If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

# GATE CS Corner    Company Wise Coding Practice

Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.
0 Average Difficulty : 0/5.0