Вы находитесь на странице: 1из 10

Operating System Assignment

Topic: Bounded Buffer problem


Group Members:

Name Roll No
H.M. Salman Zahoor B-20908
Zeeshan Ashraf B-20936

Relevant Info:

Instructor Ms. Ramsha Imran


Section A
Date 08-April-2018
Bounded Buffer Problems
Introduction
Bounded buffer problem is a classical synchronization problem for cooperating sequential
processes. A perfect example of co-operating sequential processes is producer and consumer
processes. The synchronization is needed in order to ensure that the producer stops producing
when the buffer is full and the consumer stops removing items from the buffer if it is empty. The
main complexity of this problem is that we must maintain the count for both the number of
empty and full containers that are available.

Producer produces an item and the consumer consumes. In bounded buffer environment
producer cannot produces items more than the size of buffer and consumer cannot consume
items more than buffer size. A shared memory solution to this problem exist which makes use of
a Bounded buffer problem shared variable counter initialized to 0. Producer can produce at max
Buffer-1 items.

A bounded buffer lets multiple producers and multiple consumers share a single buffer.
Producers write data to the buffer and consumers read data from the buffer.

 Producers must block if the buffer is full.


 Consumers must block if the buffer is empty.
Synchronization

A bounded buffer with capacity N has can store N data items. The places used to store the data
items inside the bounded buffer are called slots. Without proper synchronization the following
errors may occur.

 The producers doesn’t block when the buffer is full.


 A Consumer consumes an empty slot in the buffer.
 A consumer attempts to consume a slot that is only half-filled by a producer.
 Two producers writes into the same slot.
 Two consumers reads the same slot.
 And possibly more …

Problems
The problem describes two processes, which share a common, fixed-size buffer used as
a queue.
 The Producer
 The Consumer

The producer's job is to generate data, put it into the buffer, and start again. At the same time, the
consumer is consuming the data (i.e., removing it from the buffer), one piece at a time. The
problem is to make sure that the producer won't try to add data into the buffer if it's full and that
the consumer won't try to remove data from an empty buffer.

Solutions
The solution for the producer is to either go to sleep or discard data if the buffer is full. The next
time the consumer removes an item from the buffer, it notifies the producer, who starts to fill the
buffer again. In the same way, the consumer can go to sleep if it finds the buffer empty. The next
time the producer puts data into the buffer, it wakes up the sleeping consumer.
The solution can be reached by means of inter-process communication, typically
using semaphores. An inadequate solution could result in a deadlock where both processes are
waiting to be awakened. The problem can also be generalized to have multiple producers and
consumers.
1. Inadequate Implementation
To solve the problem, some programmer might come up with a solution shown below. In
the solution two library routines are used, sleep and wakeup . When sleep is called, the
caller is blocked until another process wakes it up by using the wakeup routine. The
global variable itemCount holds the number of items in the buffer.

//Integer ItemCount
int itemCount = 0;

//Procedure Function
procedure producer()
{
//While Loop
while (true)
{

item = produceItem();

//Check If ItemCount is equal to Buffer Size


if (itemCount == BUFFER_SIZE)
{
//Sleep Mode Call
sleep();
}

putItemIntoBuffer(item);
//Increment in itemCount
itemCount = itemCount + 1;

//Check If ItemCount is equal to 1


if (itemCount == 1)
{
wakeup(consumer);
}
}
}

procedure consumer()
{
while (true)
{

//Check If ItemCount==0
if (itemCount == 0)
{
//Sleep Mode Call
sleep();
}

//Set Value in item


item = removeItemFromBuffer();
//Decrement in ItemCount
itemCount = itemCount - 1;
//Check If ItemCount is equal to one less then buffer size
if (itemCount == BUFFER_SIZE - 1)
{
wakeup(producer);
}

consumeItem(item);
}
}
Problem with this solution
The problem with this solution is that it contains a race condition that can lead to a deadlock.
Consider the following scenario:
The consumer has just read the variable itemCount, noticed its zero and is just about to move
inside the if block.

1. Just before calling sleep, the consumer is interrupted and the producer is resumed.
2. The producer creates an item, puts it into the buffer, and increases itemCount .
3. Because the buffer was empty prior to the last addition, the producer tries to wake up the
consumer.
4. Unfortunately, the consumer wasn't yet sleeping, and the wakeup call is lost. When the
consumer resumes, it goes to sleep and will never be awakened again. This is because the
consumer is only awakened by the producer when itemCount is equal to 1.
5. The producer will loop until the buffer is full, after which it will also go to sleep.
Since both processes will sleep forever, we have run into a deadlock. This solution
therefore is unsatisfactory.
An alternative analysis is that if the programming language does not define the semantics
of concurrent accesses to shared variables (in this case itemCount ) with use of
synchronization, then the solution is unsatisfactory for that reason, without needing to
explicitly demonstrate a race condition.
2. Using Semaphores

//Including Libraries
#include<stdio.h>
#include<stdlib.h>

//Declear Integer Values


int mutex=1,full=0,empty=3,x=0;

//Main Body
int main()
{
int n;
//Call Producer Function
void producer();
//Call Consumer Function
void consumer();
//Call Wait Function
int wait(int);
//Call Signal Function
int signal(int);
//Print Message
printf("\n1.Producer\n2.Consumer\n3.Exit");
//While Loop
while(1)
{
//Print Message
printf("\nEnter your choice:");
//Getting Input From User
scanf("%d",&n);\
//Switch To Check Input
switch(n)
{
//Check If Mutrex is equal To 1 or empty not equal to zero than
Call
//Producer Function
case 1: if((mutex==1)&&(empty!=0))
producer();
else
printf("Buffer is full!!");
break;
//Check If Mutrex is equal To 1 or Full not equal to zero than Calll
//Producer Function
case 2: if((mutex==1)&&(full!=0))
consumer();
else
printf("Buffer is empty!!");
break;
case 3:
exit(0);
break;
}
}

return 0;
}

//Wait Function
int wait(int s)
{
return (--s);
}
//Signal Function
int signal(int s)
{
return(++s);
}

//Producer Function
void producer()
{
//Store Value In mutex from wait Function
mutex=wait(mutex);
//Store Value In full from signal Function
full=signal(full);
//Store Value In empty from wait Function
empty=wait(empty);
//Increment in x
x++;
//Print Message
printf("\nProducer produces the item %d",x);
//Store Value In mutex from Signal Function
mutex=signal(mutex);
}

//Consumer Function
void consumer()
{
//Store Value In mutex from wait Function
mutex=wait(mutex);
//Store Value In full from wait Function
full=wait(full);
//Store Value In empty from signal Function
empty=signal(empty);
//Print Message
printf("\nConsumer consumes item %d",x);
//Descrement in X Value
x--;
//Store Value In mutex from signal Function
mutex=signal(mutex);
}

Explanation
As you can see, the calls to empty( ) and full( ) are synchronized, i.e. each call to full ( )
is followed by a call to empty( ) and no items are missed. Without the semaphores,
multiple calls to fulll() would have occurred without matching calls to empty(), resulting
in items being missed. (To prove this, remove the semaphore code and observe the
results.)
The sequencing of empty() and full() calls is handled by two semaphores: mutex
.
 Before signal( ) can produce an item, it must acquire a permit from mutex. After it
has produce the item, it reduces the value of empty( ).
 Before wait( ) can consume an item, it must acquire a permit from mutex. After it
consumes the item, it reduces the value of full( ).
 This “give and take” mechanism ensures that each call to signal( ) must be followed
by a call to wait( ).
Producer Function

 Looking at the above code for a producer, we can see that a producer first waits until there is
at least one empty slot.
 Then it decrements the empty semaphore because, there will now be one less empty slot,
since the producer is going to insert data in one of those slots.
 Then, it acquires lock on the buffer, so that the consumer cannot access the buffer until
producer completes its operation.
 After performing the insert operation, the lock is released and the value of full is incremented
because the producer has just filled a slot in the buffer.

Consumer Function

 The consumer waits until there is at least one full slot in the buffer.
 Then it decrements the full semaphore because the number of occupied slots will be
decreased by one, after the consumer completes its operation.
 After that, the consumer acquires lock on the buffer.
 Following that, the consumer completes the removal operation so that the data from one of
the full slots is removed.
 Then, the consumer releases the lock.
 Finally, the empty semaphore is incremented by 1, because the consumer has just removed
data from an occupied slot, thus making it empty.

Вам также может понравиться