Open In App

Peterson’s Algorithm in Process Synchronization

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

Prerequisite – Synchronization, Critical Section 

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. Producers produce an item and put it into the buffer. If the buffer is already full then the producer will have to wait for an empty block in the buffer. Consumers consume an item from the buffer. If the buffer is already empty then the consumer will have to wait for an item in the 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 – 

C++
#include <iostream>
#include <thread>
#include <vector>

const int N = 2; // Number of threads (producer and consumer)

std::vector<bool> flag(N, false); // Flags to indicate readiness
int turn = 0; // Variable to indicate turn

void producer(int j) {
    do {
        flag[j] = true; // Producer j is ready to produce
        turn = 1 - j;   // Allow consumer to consume
        while (flag[1 - j] && turn == 1 - j) {
            // Wait for consumer to finish
            // Producer waits if consumer is ready and it's consumer's turn
        }

        // Critical Section: Producer produces an item and puts it into the buffer

        flag[j] = false; // Producer is out of the critical section

        // Remainder Section: Additional actions after critical section
    } while (true); // Continue indefinitely
}

void consumer(int i) {
    do {
        flag[i] = true; // Consumer i is ready to consume
        turn = i;       // Allow producer to produce
        while (flag[1 - i] && turn == i) {
            // Wait for producer to finish
            // Consumer waits if producer is ready and it's producer's turn
        }

        // Critical Section: Consumer consumes an item from the buffer

        flag[i] = false; // Consumer is out of the critical section

        // Remainder Section: Additional actions after critical section
    } while (true); // Continue indefinitely
}

int main() {
    std::thread producerThread(producer, 0); // Create producer thread
    std::thread consumerThread(consumer, 1); // Create consumer thread

    producerThread.join(); // Wait for producer thread to finish
    consumerThread.join(); // Wait for consumer thread to finish

    return 0;
}
C
// code for producer (j)

// producer j is ready
// 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 &amp;&amp; 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

    // consumer i is ready
    // 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 &amp;&amp; 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
Java
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Main {
    static final int N = 2; // Number of threads (producer and consumer)
    static final Lock lock = new ReentrantLock();
    static final Condition[] readyToProduce = {lock.newCondition(), lock.newCondition()};
    static volatile int turn = 0; // Variable to indicate turn

    static void producer(int j) {
        do {
            lock.lock();
            try {
                while (turn != j) {
                    readyToProduce[j].await();
                }

                // Critical Section: Producer produces an item and puts it into the buffer
                System.out.println("Producer " + j + " produces an item.");

                turn = 1 - j; // Allow consumer to consume
                readyToProduce[1 - j].signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

            // Remainder Section: Additional actions after critical section
        } while (true); // Continue indefinitely
    }

    static void consumer(int i) {
        do {
            lock.lock();
            try {
                while (turn != i) {
                    readyToProduce[i].await();
                }

                // Critical Section: Consumer consumes an item from the buffer
                System.out.println("Consumer " + i + " consumes an item.");

                turn = 1 - i; // Allow producer to produce
                readyToProduce[1 - i].signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }

            // Remainder Section: Additional actions after critical section
        } while (true); // Continue indefinitely
    }

    public static void main(String[] args) {
        Thread producerThread = new Thread(() -> producer(0)); // Create producer thread
        Thread consumerThread = new Thread(() -> consumer(1)); // Create consumer thread

        producerThread.start(); // Start producer thread
        consumerThread.start(); // Start consumer thread

        try {
            Thread.sleep(1000); // Run for 1 second
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            producerThread.interrupt(); // Interrupt producer thread
            consumerThread.interrupt(); // Interrupt consumer thread
        }
    }
}
C#
using System;
using System.Threading;
using System.Collections.Generic;

class GFG
{
    const int N = 2; // Number of threads
    static List<bool> flag = new List<bool>(new bool[N]);
    static int turn = 0; // Variable to indicate turn
    // Producer method
    static void Producer(object obj)
    {
        int j = (int)obj;
        do
        {
            flag[j] = true;
            turn = 1 - j;
            // Wait for consumer to finish
            // Producer waits if consumer is ready and it's consumer's turn
            while (flag[1 - j] && turn == 1 - j)
            {
                // Wait
            }
            // Critical Section: Producer produces an item and 
            // puts it into the buffer
            Console.WriteLine($"Producer {j} produced an item");
            flag[j] = false;
            // Remainder Section: Additional actions after critical section
            Thread.Sleep(1000);

        } while (true);
    }
    // Consumer method
    static void Consumer(object obj)
    {
        int i = (int)obj;
        do
        {
            flag[i] = true;
            turn = i;
            // Wait for producer to finish
            // Consumer waits if producer is ready and it's producer's turn
            while (flag[1 - i] && turn == i)
            {
                // Wait
            }
            // Critical Section: Consumer consumes an item from buffer
            Console.WriteLine($"Consumer {i} consumed an item");
            flag[i] = false;
            // Remainder Section: Additional actions after critical section
            Thread.Sleep(1000);
        } while (true);
    }
    static void Main(string[] args)
    {
        Thread producerThread = new Thread(Producer); // Create producer thread
        Thread consumerThread = new Thread(Consumer); // Create consumer thread
        producerThread.Start(0); // Start producer thread with index 0
        consumerThread.Start(1); // Start consumer thread with index 1
        producerThread.Join(); // Wait for producer thread to finish
        consumerThread.Join(); // Wait for consumer thread to finish
    }
}
Javascript
const N = 2; // Number of threads (producer and consumer)
const lockObject = {}; // Lock object for synchronization

async function producer(j) {
    while (true) {
        await new Promise((resolve) => {
            lock(lockObject, () => {
                // Critical Section: Producer produces an item and puts it into the buffer
                console.log(`Producer ${j} produces an item`);
                // Remainder Section: Additional actions after the critical section
            });
            resolve();
        });
        await sleep(100); // Simulate some work before the next iteration
    }
}

async function consumer(i) {
    while (true) {
        await new Promise((resolve) => {
            lock(lockObject, () => {
                // Critical Section: Consumer consumes an item from the buffer
                console.log(`Consumer ${i} consumes an item`);
                // Remainder Section: Additional actions after the critical section
            });
            resolve();
        });
        await sleep(100); // Simulate some work before the next iteration
    }
}

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

function lock(obj, callback) {
    if (!obj.__lock__) {
        obj.__lock__ = true;
        try {
            callback();
        } finally {
            delete obj.__lock__;
        }
    }
}

// Start producer and consumer threads
producer(0); // Start producer 0
producer(1); // Start producer 1
consumer(0); // Start consumer 0
consumer(1); // Start consumer 1

// Run for 1 second
setTimeout(() => {
    process.exit(); // Terminate the program after 1 second
}, 1000);
Python3
import threading

N = 2  # Number of threads (producer and consumer)
flag = [False] * N  # Flags to indicate readiness
turn = 0  # Variable to indicate turn

# Function for producer thread
def producer(j):
    while True:
        flag[j] = True  # Producer j is ready to produce
        turn = 1 - j  # Allow consumer to consume
        while flag[1 - j] and turn == 1 - j:
            # Wait for consumer to finish
            # Producer waits if consumer is ready and it's consumer's turn
            pass

        # Critical Section: Producer produces an item and puts it into the buffer

        flag[j] = False  # Producer is out of the critical section

        # Remainder Section: Additional actions after critical section

# Function for consumer thread
def consumer(i):
    while True:
        flag[i] = True  # Consumer i is ready to consume
        turn = i  # Allow producer to produce
        while flag[1 - i] and turn == i:
            # Wait for producer to finish
            # Consumer waits if producer is ready and it's producer's turn
            pass

        # Critical Section: Consumer consumes an item from the buffer

        flag[i] = False  # Consumer is out of the critical section

        # Remainder Section: Additional actions after critical section

# Create producer and consumer threads
producer_thread = threading.Thread(target=producer, args=(0,))
consumer_thread = threading.Thread(target=consumer, args=(1,))

# Start the threads
producer_thread.start()
consumer_thread.start()

# Wait for the threads to finish
producer_thread.join()
consumer_thread.join()

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 its flag to true and turn into 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 its 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, indicating 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 macro RT. 

C++
#include <iostream>
#include <vector>

#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/time.h>

#define BSIZE 8
#define PWT 2
#define CWT 10
#define RT 10

int shmid1, shmid2, shmid3, shmid4;
key_t k1 = 5491, k2 = 5812, k3 = 4327, k4 = 3213;

bool* SHM1;
int* SHM2;
int* SHM3;

void initializeBuffer(int* buf, int size) {
    for (int i = 0; i < size; ++i) {
        buf[i] = 0;
    }
}

int myrand(int n) {
    static int initialized = 0;
    if (!initialized) {
        srand(static_cast<unsigned>(time(nullptr)));
        initialized = 1;
    }
    return (rand() % n + 1);
}

void cleanup() {
    shmdt(SHM1);
    shmdt(SHM2);
    shmdt(SHM3);
    shmctl(shmid1, IPC_RMID, nullptr);
    shmctl(shmid2, IPC_RMID, nullptr);
    shmctl(shmid3, IPC_RMID, nullptr);
    shmctl(shmid4, IPC_RMID, nullptr);
}

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

    if (shmid1 < 0 || shmid2 < 0 || shmid3 < 0 || shmid4 < 0) {
        perror("Main shmget error: ");
        exit(1);
    }

    SHM3 = static_cast<int*>(shmat(shmid3, nullptr, 0));
    initializeBuffer(SHM3, BSIZE);

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

    int* state = static_cast<int*>(shmat(shmid4, nullptr, 0));
    *state = 1;
    int wait_time;

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

    if (fork() == 0) // Producer code
    {
        SHM1 = static_cast<bool*>(shmat(shmid1, nullptr, 0));
        SHM2 = static_cast<int*>(shmat(shmid2, nullptr, 0));
        SHM3 = static_cast<int*>(shmat(shmid3, nullptr, 0));

        if (SHM1 == nullptr || SHM2 == nullptr || SHM3 == nullptr) {
            perror("Producer shmat error: ");
            exit(1);
        }

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

        while (*state == 1) {
            flag[j] = true;
            printf("Producer is ready now.\n\n");
            *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);

#ifdef _WIN32
            Sleep(wait_time * 1000);
#else
            usleep(wait_time * 1000000);
#endif
        }

        exit(0);
    }

    if (fork() == 0) // Consumer code
    {
        SHM1 = static_cast<bool*>(shmat(shmid1, nullptr, 0));
        SHM2 = static_cast<int*>(shmat(shmid2, nullptr, 0));
        SHM3 = static_cast<int*>(shmat(shmid3, nullptr, 0));

        if (SHM1 == nullptr || SHM2 == nullptr || SHM3 == nullptr) {
            perror("Consumer shmat error:");
            exit(1);
        }

        bool* flag = SHM1;
        int* turn = SHM2;
        int* buf = SHM3;
        int index = 0;
        flag[i] = false;

        while (*state == 1) {
            flag[i] = true;
            printf("Consumer is ready now.\n\n");
            *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) {
                    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);

#ifdef _WIN32
            Sleep(wait_time * 1000);
#else
            usleep(wait_time * 1000000);
#endif
        }

        exit(0);
    }

    // Parent process will now wait for RT seconds before causing the child to terminate
    while (1) {
        gettimeofday(&t, nullptr);
        time_t t2 = t.tv_sec;
        if (t2 - t1 > RT) {
            *state = 0;
            break;
        }
    }

    // Waiting for both processes to exit
    wait(nullptr);
    wait(nullptr);

    cleanup();
    printf("The clock ran out.\n");

    return 0;
}
C
// C program to implement Peterson’s Algorithm
// for producer-consumer problem.
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;time.h&gt;
#include &lt;sys/types.h&gt;
#include &lt;sys/ipc.h&gt;
#include &lt;sys/shm.h&gt;
#include &lt;stdbool.h&gt;
#define _BSD_SOURCE
#include &lt;sys/time.h&gt;

#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(&amp;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 &lt; 0 || shmid2 &lt; 0 || shmid3 &lt; 0 || shmid4 &lt; 0) {
        perror(&quot;Main shmget error: &quot;);
        exit(1);
    }
    SHM3 = (int*)shmat(shmid3, NULL, 0);
    int ix = 0;
    while (ix &lt; BSIZE) // Initializing buffer
        SHM3[ix++] = 0;

    struct timeval t;
    time_t t1, t2;
    gettimeofday(&amp;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(&quot;Producer shmat error: &quot;);
            exit(1);
        }

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

        while (*state == 1) {
            flag[j] = true;
            printf(&quot;Producer is ready now.\n\n&quot;);
            *turn = i;
            while (flag[i] == true &amp;&amp; *turn == i)
                ;

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

            flag[j] = false;
            if (*state == 0)
                break;
            wait_time = myrand(PWT);
            printf(&quot;Producer will wait for %d seconds\n\n&quot;, 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(&quot;Consumer shmat error:&quot;);
            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;
            printf(&quot;Consumer is ready now.\n\n&quot;);
            *turn = j;
            while (flag[j] == true &amp;&amp; *turn == j)
                ;

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

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

class Program
{
    const int BSIZE = 8;
    const int PWT = 2;
    const int CWT = 10;
    const int RT = 10;

    static bool[] SHM1 = new bool[2];
    static int[] SHM2 = new int[1];
    static int[] SHM3 = new int[BSIZE];

    static Random rand = new Random();

    static void InitializeBuffer(int[] buf, int size)
    {
        Array.Fill(buf, 0);
    }

    static int MyRand(int n) => rand.Next(1, n + 1);

    static async Task Producer()
    {
        bool[] flag = SHM1;
        int[] turn = SHM2;
        int[] buf = SHM3;
        int index = 0;

        while (SHM2[0] == 1)
        {
            flag[1] = true;
            Console.WriteLine("Producer is ready now.\n");

            turn[0] = 0;
            while (flag[0] && turn[0] == 0) ;

            // Critical Section Begin
            index = 0;
            while (index < BSIZE)
            {
                if (buf[index] == 0)
                {
                    int tempo = MyRand(BSIZE * 3);
                    Console.WriteLine($"Job {tempo} has been produced");
                    buf[index] = tempo;
                    break;
                }
                index++;
            }

            if (index == BSIZE)
                Console.WriteLine("Buffer is full, nothing can be produced!!!\n");

            Console.Write("Buffer: ");
            index = 0;
            while (index < BSIZE)
                Console.Write($"{buf[index++]} ");
            Console.WriteLine("\n");
            // Critical Section End

            flag[1] = false;

            if (SHM2[0] == 0)
                break;

            int waitTime = MyRand(PWT);
            Console.WriteLine($"Producer will wait for {waitTime} seconds\n");

            await Task.Delay(waitTime * 1000);
        }
    }

    static async Task Consumer()
    {
        bool[] flag = SHM1;
        int[] turn = SHM2;
        int[] buf = SHM3;
        int index = 0;
        flag[0] = false;

        while (SHM2[0] == 1)
        {
            flag[0] = true;
            Console.WriteLine("Consumer is ready now.\n");

            turn[0] = 1;
            while (flag[1] && turn[0] == 1) ;

            // Critical Section Begin
            if (buf[0] != 0)
            {
                Console.WriteLine($"Job {buf[0]} has been consumed");
                buf[0] = 0;
                index = 1;
                while (index < BSIZE)
                {
                    buf[index - 1] = buf[index];
                    index++;
                }
                buf[index - 1] = 0;
            }
            else
                Console.WriteLine("Buffer is empty, nothing can be consumed!!!\n");

            Console.Write("Buffer: ");
            index = 0;
            while (index < BSIZE)
                Console.Write($"{buf[index++]} ");
            Console.WriteLine("\n");
            // Critical Section End

            flag[0] = false;

            if (SHM2[0] == 0)
                break;

            int waitTime = MyRand(CWT);
            Console.WriteLine($"Consumer will sleep for {waitTime} seconds\n");

            await Task.Delay(waitTime * 1000);
        }
    }

    static async Task Main()
    {
        InitializeBuffer(SHM3, BSIZE);

        DateTime startTime = DateTime.Now;

        SHM2[0] = 1; // Initializing the state

        var producerTask = Producer();
        var consumerTask = Consumer();

        // Parent process will now wait for RT seconds before causing the child to terminate
        while ((DateTime.Now - startTime).TotalSeconds <= RT) ;

        SHM2[0] = 0;

        // Waiting for both tasks to finish
        await Task.WhenAll(producerTask, consumerTask);

        Console.WriteLine("The clock ran out.\n");
    }
}

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
Producer is ready now.
Job 8 has been produced
Buffer: 9 8 0 0 0 0 0 0
Producer will wait for 2 seconds
Producer is ready now.
Job 13 has been produced
Buffer: 9 8 13 0 0 0 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 23 has been produced
Buffer: 9 8 13 23 0 0 0 0
Producer will wait for 1 seconds
Consumer is ready now.
Job 9 has been consumed
Buffer: 8 13 23 0 0 0 0 0
Consumer will sleep for 9 seconds
Producer is ready now.
Job 15 has been produced
Buffer: 8 13 23 15 0 0 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 13 has been produced
Buffer: 8 13 23 15 13 0 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 11 has been produced
Buffer: 8 13 23 15 13 11 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 22 has been produced
Buffer: 8 13 23 15 13 11 22 0
Producer will wait for 2 seconds
Producer is ready now.
Job 23 has been produced
Buffer: 8 13 23 15 13 11 22 23
Producer will wait for 1 seconds
The clock ran out.
C++
//g++ -pthread /path/to/your/Solution.cpp -o your_program_name
//In environments where threading is not supported by default, you need to explicitly link against the pthread library.
#include <iostream>
#include <vector>
#include <chrono>
#include <cstdlib>
#include <ctime>
#include <thread>


const int BSIZE = 8;
const int PWT = 1000;
const int CWT = 4000;
const int RT = 30000;

bool shmid1 = false;
int shmid2 = 0;
std::vector<int> shmid3(BSIZE, 0);
int shmid4 = 0;

int state = 1;

int myrand(int n) {
    return rand() % n + 1;
}

void producer() {
    while (state == 1) {
        shmid1 = true;
        std::cout << "Producer is ready now.\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(500));

        shmid2 = 0;
        while (shmid1 && shmid2 == 0) {}

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

        shmid1 = false;
        if (state == 0) break;
        const int wait_time = myrand(PWT);
        std::cout << "Producer will wait for " << wait_time / 1000.0 << " seconds\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(wait_time));
    }
}

void consumer() {
    shmid1 = false;
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    while (state == 1) {
        shmid1 = true;
        std::cout << "Consumer is ready now.\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(500));

        shmid2 = 1;
        while (shmid1 && shmid2 == 1) {}

        // Critical Section Begin
        if (shmid3[0] != 0) {
            std::cout << "Job " << shmid3[0] << " has been consumed\n";
            shmid3[0] = 0;
            int index = 1;
            while (index < BSIZE) {
                shmid3[index - 1] = shmid3[index];
                index++;
            }
            shmid3[index - 1] = 0;
        } else {
            std::cout << "Buffer is empty, nothing can be consumed!!!\n";
        }
        std::cout << "Buffer: ";
        for (int val : shmid3) {
            std::cout << val << " ";
        }
        std::cout << "\n";
        // Critical Section End

        shmid1 = false;
        if (state == 0) break;
        const int wait_time = myrand(CWT);
        std::cout << "Consumer will sleep for " << wait_time / 1000.0 << " seconds\n";
        std::this_thread::sleep_for(std::chrono::milliseconds(wait_time));
    }
}

int main() {
    srand(time(nullptr));

    // Start producer and consumer in separate threads (simulated)
    std::thread producer_thread(producer);
    std::thread consumer_thread(consumer);

    // Simulate program run for RT milliseconds
    for (int elapsed_time = 0; elapsed_time < RT; elapsed_time += 100) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }

    // Set state to 0 to stop producer and consumer
    state = 0;

    // Join threads
    producer_thread.join();
    consumer_thread.join();

    std::cout << "The clock ran out.\n";

    return 0;
}
Java
import java.util.Random;

public class ProducerConsumer {
    static final int BSIZE = 8; // Buffer size
    static final int PWT = 2; // Producer wait time limit
    static final int CWT = 10; // Consumer wait time limit
    static final int RT = 10; // Program run-time in seconds
    static volatile boolean state = true;
    static volatile boolean[] flag = new boolean[2];
    static volatile int turn = 1;
    static volatile int[] buf = new int[BSIZE];

    static int myrand(int n) {
        Random rand = new Random();
        return rand.nextInt(n) + 1;
    }

    public static void main(String[] args) {
        Thread producer = new Thread(() -> {
            int index;
            while (state) {
                flag[1] = true;
                System.out.println("Producer is ready now.\n");

                turn = 0;
                while (flag[0] && turn == 0) ;

                synchronized (buf) {
                    index = 0;
                    while (index < BSIZE) {
                        if (buf[index] == 0) {
                            int tempo = myrand(BSIZE * 3);
                            System.out.println("Job " + tempo + " has been produced");
                            buf[index] = tempo;
                            break;
                        }
                        index++;
                    }
                    if (index == BSIZE)
                        System.out.println("Buffer is full, nothing can be produced!!!\n");
                    System.out.print("Buffer: ");
                    for (int value : buf) {
                        System.out.print(value + " ");
                    }
                    System.out.println("\n");
                }

                flag[1] = false;
                if (!state) break;
                int wait_time = myrand(PWT);
                System.out.println("Producer will wait for " + wait_time + " seconds\n");
                try {
                    Thread.sleep(wait_time * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        Thread consumer = new Thread(() -> {
            int index;
            flag[0] = false;
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            while (state) {
                flag[0] = true;
                System.out.println("Consumer is ready now.\n");

                turn = 1;
                while (flag[1] && turn == 1) ;

                synchronized (buf) {
                    if (buf[0] != 0) {
                        System.out.println("Job " + buf[0] + " has been consumed");
                        buf[0] = 0;
                        index = 1;
                        while (index < BSIZE) {
                            buf[index - 1] = buf[index];
                            index++;
                        }
                        buf[index - 1] = 0;
                    } else
                        System.out.println("Buffer is empty, nothing can be consumed!!!\n");

                    System.out.print("Buffer: ");
                    for (int value : buf) {
                        System.out.print(value + " ");
                    }
                    System.out.println("\n");
                }

                flag[0] = false;
                if (!state) break;
                int wait_time = myrand(CWT);
                System.out.println("Consumer will sleep for " + wait_time + " seconds\n");
                try {
                    Thread.sleep(wait_time * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        producer.start();
        consumer.start();

        try {
            Thread.sleep(RT * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        state = false;

        try {
            producer.join();
            consumer.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("The clock ran out.\n");
    }
}
C#
using System;
using System.Threading;
using System.Collections.Generic;

public class ProducerConsumer
{
    static readonly int BSIZE = 8; // Buffer size
    static readonly int PWT = 2;   // Producer wait time limit
    static readonly int CWT = 10;  // Consumer wait time limit
    static readonly int RT = 10;   // Program run-time in seconds
    static volatile bool state = true;
    static volatile bool[] flag = new bool[2];
    static volatile int turn = 1;
    static volatile int[] buf = new int[BSIZE];

    static Random rand = new Random();

    static int MyRand(int n)
    {
        return rand.Next(1, n + 1);
    }

    static void Main(string[] args)
    {
        Thread producerThread = new Thread(() =>
        {
            int index;
            while (state)
            {
                flag[1] = true;
                Console.WriteLine("Producer is ready now.\n");

                turn = 0;
                while (flag[0] && turn == 0) ;

                lock (buf)
                {
                    index = 0;
                    while (index < BSIZE)
                    {
                        if (buf[index] == 0)
                        {
                            int tempo = MyRand(BSIZE * 3);
                            Console.WriteLine($"Job {tempo} has been produced");
                            buf[index] = tempo;
                            break;
                        }
                        index++;
                    }
                    if (index == BSIZE)
                        Console.WriteLine("Buffer is full, nothing can be produced!!!\n");
                    Console.Write("Buffer: ");
                    foreach (int value in buf)
                    {
                        Console.Write($"{value} ");
                    }
                    Console.WriteLine("\n");
                }

                flag[1] = false;
                if (!state) break;
                int waitTime = MyRand(PWT);
                Console.WriteLine($"Producer will wait for {waitTime} seconds\n");
                Thread.Sleep(waitTime * 1000);
            }
        });

        Thread consumerThread = new Thread(() =>
        {
            int index;
            flag[0] = false;
            Thread.Sleep(5000);

            while (state)
            {
                flag[0] = true;
                Console.WriteLine("Consumer is ready now.\n");

                turn = 1;
                while (flag[1] && turn == 1) ;

                lock (buf)
                {
                    if (buf[0] != 0)
                    {
                        Console.WriteLine($"Job {buf[0]} has been consumed");
                        buf[0] = 0;
                        index = 1;
                        while (index < BSIZE)
                        {
                            buf[index - 1] = buf[index];
                            index++;
                        }
                        buf[index - 1] = 0;
                    }
                    else
                        Console.WriteLine("Buffer is empty, nothing can be consumed!!!\n");

                    Console.Write("Buffer: ");
                    foreach (int value in buf)
                    {
                        Console.Write($"{value} ");
                    }
                    Console.WriteLine("\n");
                }

                flag[0] = false;
                if (!state) break;
                int waitTime = MyRand(CWT);
                Console.WriteLine($"Consumer will sleep for {waitTime} seconds\n");
                Thread.Sleep(waitTime * 1000);
            }
        });

        producerThread.Start();
        consumerThread.Start();

        try
        {
            Thread.Sleep(RT * 1000);
        }
        catch (ThreadInterruptedException e)
        {
            Console.WriteLine(e.StackTrace);
        }
        state = false;

        try
        {
            producerThread.Join();
            consumerThread.Join();
        }
        catch (ThreadInterruptedException e)
        {
            Console.WriteLine(e.StackTrace);
        }

        Console.WriteLine("The clock ran out.\n");
    }
}
Javascript
const BSIZE = 8; // Buffer size
const PWT = 1000; // Producer wait time limit in milliseconds
const CWT = 4000; // Consumer wait time limit in milliseconds
const RT = 30000; // Program run-time in milliseconds

let shmid1 = false;
let shmid2 = false;
let shmid3 = new Array(BSIZE).fill(0);
let shmid4 = 0;

let state = 1;

function myrand(n) {
  return Math.floor(Math.random() * n) + 1;
}

function producer() {
  while (state === 1) {
    shmid1 = true;
    console.log("Producer is ready now.");
    // Simulate some processing time
    awaitTimeout(500);

    shmid2 = 0;
    while (shmid1 && shmid2 === 0) {}

    // Critical Section Begin
    let index = 0;
    while (index < BSIZE) {
      if (shmid3[index] === 0) {
        const tempo = myrand(BSIZE * 3);
        console.log(`Job ${tempo} has been produced`);
        shmid3[index] = tempo;
        break;
      }
      index++;
    }
    if (index === BSIZE) {
      console.log("Buffer is full, nothing can be produced!!!");
    }
    console.log("Buffer:", shmid3.join(" "));
    // Critical Section End

    shmid1 = false;
    if (state === 0) break;
    const wait_time = myrand(PWT);
    console.log(`Producer will wait for ${wait_time / 1000} seconds`);
    awaitTimeout(wait_time);
  }
}

function consumer() {
  shmid1 = false;
  awaitTimeout(5000);
  while (state === 1) {
    shmid1 = true;
    console.log("Consumer is ready now.");
    // Simulate some processing time
    awaitTimeout(500);

    shmid2 = 1;
    while (shmid1 && shmid2 === 1) {}

    // Critical Section Begin
    if (shmid3[0] !== 0) {
      console.log(`Job ${shmid3[0]} has been consumed`);
      shmid3[0] = 0;
      let index = 1;
      while (index < BSIZE) {
        shmid3[index - 1] = shmid3[index];
        index++;
      }
      shmid3[index - 1] = 0;
    } else {
      console.log("Buffer is empty, nothing can be consumed!!!");
    }
    console.log("Buffer:", shmid3.join(" "));
    // Critical Section End

    shmid1 = false;
    if (state === 0) break;
    const wait_time = myrand(CWT);
    console.log(`Consumer will sleep for ${wait_time / 1000} seconds`);
    awaitTimeout(wait_time);
  }
}

async function awaitTimeout(ms) {
  return new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

(async () => {
  producer();
  consumer();

  await awaitTimeout(RT);
  state = 0;

  console.log("The clock ran out.");
})();
Python3
import multiprocessing
import random
import time

BSIZE = 8  # Buffer size
PWT = 1  # Producer wait time limit
CWT = 4  # Consumer wait time limit
RT = 30  # Program run-time in seconds

shmid1 = multiprocessing.Value('i', 0)
shmid2 = multiprocessing.Value('i', 0)
shmid3 = multiprocessing.Array('i', [0] * BSIZE)
shmid4 = multiprocessing.Value('i', 0)

state = multiprocessing.Value('i', 1)

def myrand(n):
    return random.randint(1, n)

def producer():
    global state
    while state.value == 1:
        shmid1.value = True
        print("Producer is ready now.")
        time.sleep(0.5)  # Simulate some processing time

        shmid2.value = 0
        while shmid1.value == True and shmid2.value == 0:
            pass

        with shmid1.get_lock(), shmid3.get_lock():
            # Critical Section Begin
            index = 0
            while index < BSIZE:
                if shmid3[index] == 0:
                    tempo = myrand(BSIZE * 3)
                    print(f"Job {tempo} has been produced")
                    shmid3[index] = tempo
                    break
                index += 1
            if index == BSIZE:
                print("Buffer is full, nothing can be produced!!!")
            print("Buffer:", ' '.join(map(str, shmid3)))
            # Critical Section End

        shmid1.value = False
        if state.value == 0:
            break
        wait_time = myrand(PWT)
        print(f"Producer will wait for {wait_time} seconds")
        time.sleep(wait_time)

def consumer():
    global state
    shmid1.value = False
    time.sleep(5)
    while state.value == 1:
        shmid1.value = True
        print("Consumer is ready now.")
        time.sleep(0.5)  # Simulate some processing time

        shmid2.value = 1
        while shmid1.value == True and shmid2.value == 1:
            pass

        with shmid1.get_lock(), shmid3.get_lock():
            # Critical Section Begin
            if shmid3[0] != 0:
                print(f"Job {shmid3[0]} has been consumed")
                shmid3[0] = 0
                index = 1
                while index < BSIZE:
                    shmid3[index - 1] = shmid3[index]
                    index += 1
                shmid3[index - 1] = 0
            else:
                print("Buffer is empty, nothing can be consumed!!!")
            print("Buffer:", ' '.join(map(str, shmid3)))
            # Critical Section End

        shmid1.value = False
        if state.value == 0:
            break
        wait_time = myrand(CWT)
        print(f"Consumer will sleep for {wait_time} seconds")
        time.sleep(wait_time)

if __name__ == "__main__":
    producer_process = multiprocessing.Process(target=producer)
    consumer_process = multiprocessing.Process(target=consumer)

    producer_process.start()
    consumer_process.start()

    time.sleep(RT)
    state.value = 0

    producer_process.join()
    consumer_process.join()

    print("The clock ran out.")
Producer is ready now.
Job 13 has been produced
Buffer: 13 0 0 0 0 0 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 19 has been produced
Buffer: 13 19 0 0 0 0 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 24 has been produced
Buffer: 13 19 24 0 0 0 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 14 has been produced
Buffer: 13 19 24 14 0 0 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 22 has been produced
Buffer: 13 19 24 14 22 0 0 0
Producer will wait for 2 seconds
Consumer is ready now.
Job 13 has been consumed
Buffer: 19 24 14 22 0 0 0 0
Consumer will sleep for 4 seconds
Producer is ready now.
Job 21 has been produced
Buffer: 19 24 14 22 21 0 0 0
Producer will wait for 2 seconds
Producer is ready now.
Job 24 has been produced
Buffer: 19 24 14 22 21 24 0 0
Producer will wait for 2 seconds
Consumer is ready now.
Job 19 has been consumed
Buffer: 24 14 22 21 24 0 0 0
Consumer will sleep for 7 seconds
The clock ran out.


Advantages of the Peterson Solution

  1. With Peterson’s solution, multiple processes can access and share a resource without causing any resource conflicts.
  2. Every process has a chance to be carried out.
  3. It uses straightforward logic and is easy to put into practice.
  4. Since it is entirely software dependent and operates in user mode, it can be used with any hardware.
    eliminates the chance of a deadlock.

Disadvantages of the Peterson’s Solution

  1. Waiting for the other processes to exit the critical region may take a long time. We call it busy waiting.
  2. On systems that have multiple CPUs, this algorithm might not function.
  3. The Peterson solution can only run two processes concurrently.

Frequently Asked Questions

Q1:What is synchronization in concurrent programming? 

Answer:

Synchronization refers to the coordination of multiple processes or threads to achieve a desired outcome. It involves using synchronization mechanisms like locks, semaphores, or mutexes to control access to shared resources and prevent race conditions or conflicts.

Q2:What are the common synchronization mechanisms used in concurrent programming? 

Answer:

Common synchronization mechanisms include locks, semaphores, condition variables, monitors, and atomic operations. These mechanisms provide ways to control access to shared resources and coordinate the execution of concurrent processes or threads.

If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.



Last Updated : 14 Mar, 2024
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads