You are on page 1of 5

Producer-Consumer Problem using Semaphores

One of the classic synchronization problems is the bounded buffer problem,


commonly known as the producer-consumer problem.
In the producer-consumer problem, there is one Producer who produces
things, and there is one Consumer who consumes the products which are
produced by the producer. The producers and consumers share the same fixed-
size memory buffer.
The Producer's role is to produce data, store it in the buffer, and then generate
data again. The Consumer's task is to consume the data from the buffer.
The Producer-Consumer problem is a classic multi-process synchronization
problem, which implies we're aiming to synchronize many processes.
When the consumer is consuming an item from the buffer, the producer should
not add items into the buffer, and vice versa. As a result, only one producer or
consumer should access the buffer at a time.

What's the problem here?


Let's consider that there are n slots in the buffer, and each slot may store one
unit of data. On the buffer, there are two processes running: producer and
consumer.

A producer tries to fill an empty space in the buffer with data. A consumer
attempts to retrieve data from that buffer slot. If those two processes run
concurrently, as you may have anticipated, they will not give the desired
outcome.
There must be a method to make both the producer and the customer operate
independently.
The following are some of the issues that might arise in the Producer-Consumer:
 The producer should generate data only if the buffer is not full. When the
buffer is filled, the producer should not be able to add any more data to it.
 When the buffer is not empty, the consumer can consume the data. The
consumer should not be able to take any data from the buffer if it is empty.
 The buffer should not be used by both the producer and the consumer at the
same time.

What’s the solution then?


Semaphores can be used to solve the three difficulties listed above. A
semaphore S is an integer variable with just two standard operations: wait() and
signal().
The signal() method increases the value of semaphore by one, whereas the
wait() operation decreases it by one.
wait(S){
while(S<=0); // busy waiting in the while loop
S--; // decreasing S by one
}

signal(S){
S++; // increasing S by one
}
 
There are two types of semaphores:
Binary Semaphore - This is related to, but not the same as, a mutex lock. It can
only have two possible values: 0 and 1. Its value is set to 1 at the start. It is used
to implement a solution to a critical section problem including multiple processes.
Counting Semaphore - Its value can traverse an unbounded domain. It's used
to limit who has access to a resource with numerous instances.
To solve this problem, We employ three semaphore variables:-
 mutex - The lock is acquired and released using a mutex, a binary
semaphore.
 empty - empty is a counting semaphore that is initialized on the basis of the
number of slots present in the buffer, at first all the slots are empty.
 full - a counting semaphore with a value of zero as its starting value.
At any particular time, the current value of empty denotes the number of vacant
slots in the buffer, while full denotes the number of occupied slots.

The Producer Solution


The pseudocode for the producer function will look like this:
do
{
   // process will wait until the empty > 0 and further decrement of 'empty'
   wait(empty);  
   // To acquire the lock
   wait(mutex); 
  
   /* Here we will perform the insert operation in a particular slot */
  
   // To release the lock
   signal(mutex); 
   // increment of 'full'
   signal(full);  
}
while(TRUE)
 
 When we look at the above code for a producer, we can see that it first waits
until at least one slot is vacant.
 wait(empty) decreases the value of the semaphore variable "empty" by one,
indicating that when the producer produces anything, the value of the empty
space in the buffer decreases. If the buffer is full, or the value of the
semaphore variable "empty" is 0, the program will stop and no production will
take place.
 wait(mutex) sets the semaphore variable "mutex" to zero, preventing any
other process from entering the critical section.
 The buffer is then locked, preventing the consumer from accessing it until the
producer completes its function.
 signal(mutex) is being used to mark the semaphore variable "mutex" to "1" so
that other processes can arrive into the critical section though because the
production is finished and the insert operation is also done.
 So, After the producer has filled a slot in the buffer, the lock is released.
 signal(full) is utilized to increase the semaphore variable "full" by one because
after inserting the data into the buffer, one slot is filled in the buffer and the
variable "full" must be updated.
This is how we address the producer section of the producer-consumer problem.
The Producer Solution
The pseudocode for the producer function will look like this:
do
{
   // process will wait until the empty > 0 and further decrement of 'empty'
   wait(empty);  
   // To acquire the lock
   wait(mutex); 
  
   /* Here we will perform the insert operation in a particular slot */
  
   // To release the lock
   signal(mutex); 
   // increment of 'full'
   signal(full);  
}
while(TRUE)
 
 When we look at the above code for a producer, we can see that it first waits
until at least one slot is vacant.
 wait(empty) decreases the value of the semaphore variable "empty" by one,
indicating that when the producer produces anything, the value of the empty
space in the buffer decreases. If the buffer is full, or the value of the
semaphore variable "empty" is 0, the program will stop and no production will
take place.
 wait(mutex) sets the semaphore variable "mutex" to zero, preventing any
other process from entering the critical section.
 The buffer is then locked, preventing the consumer from accessing it until the
producer completes its function.
 signal(mutex) is being used to mark the semaphore variable "mutex" to "1" so
that other processes can arrive into the critical section though because the
production is finished and the insert operation is also done.
 So, After the producer has filled a slot in the buffer, the lock is released.
 signal(full) is utilized to increase the semaphore variable "full" by one because
after inserting the data into the buffer, one slot is filled in the buffer and the
variable "full" must be updated.
This is how we address the producer section of the producer-consumer problem.
The Consumer Solution
The pseudocode for the producer function will look like this:
do
{
   // need to wait until full > 0 and then decrement the 'full'
   wait(full);
   // To acquire the lock
   wait(mutex); 
  
    /* Here we will perform the remove operation in a particular slot */
  
   // To release the lock
   signal(mutex);
   // increment of 'empty'
   signal(empty);
}
while(TRUE);
 
 The consumer waits until the buffer has at least one full slot.
 wait(full) is used to reduce the semaphore variable "full" by one since the
variable "full" must be reduced by one of the consumers consuming some
data.
 wait(mutex) sets the semaphore variable "mutex" to "0", preventing any other
processes from entering the critical section.
 And soon after that, the consumer then acquires a lock on the buffer.
 The consumer then completes the data removal operation by removing data
from one of the filled slots.
 So because the consumption and remove operations are complete,
signal(mutex) is being used to set the semaphore variable "mutex" to "1" so
that other processes can enter the critical section now.
 The lock is then released by the consumer.
 Because one slot space in the buffer is released after extracting the data from
the buffer, signal(empty) is used to raise the variable "empty" by one.
This is how we overcome the producer-consumer problem.

You might also like