Open In App

Producer Consumer Problem and its Implementation with C++

Improve
Improve
Like Article
Like
Save
Share
Report

Overview :
In this article, we will discuss the Producer-Consumer Problem and its Implementation with C++. The Producer-Consumer problem is a classical two-process synchronization problem. Let’s discuss it one by one.

Problem Statement :
There is one Producer and one Consumer in the producer-consumer problem.

  1. Producer – 
    The producer process executes a set of statements int produce to create a data element and stores it in the buffer.
  2. Consumer – 
    If the buffer has items, a consumer process executes a statement consume with the data element as a parameter.

Solution :  
The problem arises because the process is not synchronized because of which the items produced and consumed may not be consistent. In order to solve this problem, we use semaphore for solving this problem i.e. problem of the critical section.

Implementation in C++ :
This problem can be further subdivided into two parts as follows.

Part-1: Where the buffer size is infinite –
In this case, the buffer from where the producer stores the item and the consumer consumes the item size is not fixed.

C++14




#include<bits/stdc++.h>
#include<pthread.h>
#include<semaphore.h>
#include <unistd.h> 
using namespace std;
  
// Declaration
int r1,total_produced=0,total_consume=0;
  
// Semaphore declaration
sem_t notEmpty;
  
// Producer Section
void* produce(void *arg){
    while(1){
      cout<<"Producer produces item."<<endl;
      cout<<"Total produced = "<<++total_produced<<
        " Total consume = "<<total_consume*-1<<endl;
      sem_post(¬Empty);    
      sleep(rand()%100*0.01);
    }
}
  
// Consumer Section
void* consume(void *arg){
    while(1){
      sem_wait(¬Empty);
      cout<<"Consumer consumes item."<<endl;    
      cout<<"Total produced = "<<total_produced<<
        " Total consume = "<<(--total_consume)*-1<<endl;
      sleep(rand()%100*0.01);
    }    
}
  
int main(int argv,char *argc[]){
  
    // thread declaration
    pthread_t producer,consumer;
  
    // Declaration of attribute......
    pthread_attr_t attr;
  
    // semaphore initialization
    sem_init(¬Empty,0,0);
  
    // pthread_attr_t initialization
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
  
    // Creation of process
    r1=pthread_create(&producer,&attr,produce,NULL);
    if(r1){
      cout<<"Error in creating thread"<<endl;
      exit(-1);
    }
  
    r1=pthread_create(&consumer,&attr,consume,NULL);
    if(r1){
      cout<<"Error in creating thread"<<endl;
      exit(-1);
    }
  
    // destroying the pthread_attr
    pthread_attr_destroy(&attr);
  
    // Joining the thread
    r1=pthread_join(producer,NULL);
    if(r1){
      cout<<"Error in joining thread"<<endl;
      exit(-1);
    }
  
    r1=pthread_join(consumer,NULL);
    if(r1){
      cout<<"Error in joining thread"<<endl;
      exit(-1);
    }
  
    // Exiting thread
    pthread_exit(NULL);
  
    return 0;
}


Part-2: Where the buffer size is fixed or finite –
In this case, the buffer from where the producer stores the item and the consumer consumes the item size is fixed.

C++14




#include <bits/stdc++.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
using namespace std;
  
// Declaration
int r1, items = 0;
  
// Semaphore declaration
sem_t notEmpty, notFull;
  
// Producer Section
void* produce(void* arg)
{
    while (1) {
        sem_wait(¬Full);
        sleep(rand() % 100 * 0.01);
        cout << 
      "Producer produces item.Items Present = "
             << ++items << endl;
        sem_post(¬Empty);
        sleep(rand() % 100 * 0.01);
    }
}
  
// Consumer Section
void* consume(void* arg)
{
    while (1) {
        sem_wait(¬Empty);
        sleep(rand() % 100 * 0.01);
        cout << 
     "Consumer consumes item.Items Present = "
             << --items << endl;
        sem_post(¬Full);
        sleep(rand() % 100 * 0.01);
    }
}
  
int main(int argv, char* argc[])
{
  
    int N;
    cout << 
      "Enter the capacity of the buffer" << endl;
    cin >> N;
  
    // thread declaration
    pthread_t producer, consumer;
  
    // Declaration of attribute......
    pthread_attr_t attr;
  
    // semaphore initialization
    sem_init(¬Empty, 0, 0);
    sem_init(¬Full, 0, N);
  
    // pthread_attr_t initialization
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr,
             PTHREAD_CREATE_JOINABLE);
  
    // Creation of process
    r1 = pthread_create(&producer, &attr, 
                        produce, NULL);
    if (r1) {
        cout << 
          "Error in creating thread" << endl;
        exit(-1);
    }
  
    r1 = pthread_create(&consumer, &attr, 
                        consume, NULL);
    if (r1) {
        cout << 
          "Error in creating thread" << endl;
        exit(-1);
    }
  
    // destroying the pthread_attr
    pthread_attr_destroy(&attr);
  
    // Joining the thread
    r1 = pthread_join(producer, NULL);
    if (r1) {
        cout << "Error in joining thread" << endl;
        exit(-1);
    }
  
    r1 = pthread_join(consumer, NULL);
    if (r1) {
        cout << "Error in joining thread" << endl;
        exit(-1);
    }
  
    // Exiting thread
    pthread_exit(NULL);
  
    return 0;
}




Last Updated : 31 May, 2021
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads