650 likes | 1.32k Views
PRODUCER CONSUMER PROBLEM. Prepared By Sarath S Menon S6 CSE. Imagine a scenario in which there exists two Distinct processes both operating on a single shared data area.
E N D
PRODUCER CONSUMER PROBLEM Prepared By Sarath S Menon S6 CSE
Imagine a scenario in which there exists two Distinct processes both operating on a single shared data area. • One process, the Producer inserts information into the data area whilst the other process, the Consumer, removes information from that same area. • In order for the Producer to insert information into the data area, there must be enough space. The Producer's sole function is to insert data into the data-area, it is not allowed to remove any data from the area. • Similarly, for the Consumer to be able to remove information from the data area, there must be information there in the first place. Once again, the sole function of the Consumer is to remove data from the data area. If no data is present then the Consumer is not allowed to insert some data of it's own to later be removed by itself. T90
In computer science, the producer-consumer problem (also known as the bounded-buffer problem) is a classical example of a multi-process synchronization problem. • The problem describes two processes, the producer and the consumer, who share a common, fixed-size buffer. • The producer's job is to generate a piece of 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. T90
The solution for the producer is to go to sleep if the buffer is full. • The next time the consumer removes an item from the buffer, it wakes up the producer who starts to fill the buffer again. In the same way, the consumer goes to sleep if it finds the buffer to be 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 T90
MUTEX • Mutexesare good for managing mutual exclusion to some shared resource or piece of code. A mutex is a variable that can be in one of two states, unlocked or locked. • Consequently only one bit is required to represent it, but in practice an integer is often used with 0 meaning unlocked and all other values meaning locked. • Two procedures are used with mutexes. When a thread or a process needs access to a critical region, it calls mutex_lock. If the mutex is currently unlocked (maning the critical region is available) , the call succeeds and the calling thread is free to enter the critical region. T90
On the other hand, if the mutex is already locked, the calling thread is blocked, until the thread in the critical region is finished and calls mutex unlock. If multiple threads are blocked on the mutex, one of them is chosen at random and allowed to aquire the lock. • Initialization Set full buffer slots to 0. i.e., semaphore Full = 0. Set empty buffer slots to N. i.e., semaphore empty = N. For control access to critical section set mutex to 1. i.e., semaphore mutex = 1. T90
Consumer ( ) • {WHILE (true) { P (full) P (mutex); remove-Item ( ); V (mutex); V (empty); consume-Item (Item) • } • } • Producer ( ) {WHILE (true) {produce-Item ( ); P (empty); P (mutex); enter-Item ( ) V (mutex) V (full); } } T90
Imagine… • A person is moving(shifting) to a new house. • Has a truck full of boxes to unload and carry. • Truck is on road, so boxes have to be first unloaded to the road and then carried to the house. • No one else is currently available to help T90
Person 1 does all work by himself… • Takes a lot of time and effort, but very less quantity moved. • Calls a friend to help • Work is split • One person takes boxes off the truck and line them up on the Road. • Other takes boxes off the Road and take them into house. T90
Plan works very well, work went at a fast rate. Until….. • A friend of the person on truck arrives to help. • Unloading takes place at a faster rate, the other person was unable to manage… • The person on road calls his friends… T90
Sometimes the still outpace the consumers, the Road is full and the guys have to stand around holding boxes • Sometimes the consumers outpace the producers and they're standing around the Road instead of unpacking in house T90
So everyone makes a rule: • check the road before you go there! • Unfortunately, it didn't help. • Paul and Peter, emptying opposite ends of the truck, both saw an almost full road, but clearly enough space for one more box. • So they both picked off a box, walked over, then bonked into each other (race condition!). T90
Finally a new idea shows up. It has three new rules: • Person on truck : both have to check with me to make sure there's an empty spot before you drop-off • Others below have to check with the person who made the idea to make sure there's a box before they pick up • And finally, because there's only one observer, he/she can't keep track of this if more than one guy is messing with the line. • So even if there is a green light in step 1 or 2, they still need to check to make sure no one else is on the line. T90
New Rules… • People on truck: waitFor(spaceOnRoad) waitFor(permissionToUseRoad) dropBoxOnRoad(box) nowSomeoneElseCanUse(permissionToUseRoad) nowSomeoneElseCanUse(boxesOnRoad) • Others: • complementary T90
Algorithm Step 1: Set maximum buffer size, maximum producer and consumer threads. Step 2: Read buffer size, number of producer and consumer threads from the user. Step 3: Initialize the threads and set concurrency to the sum of both threads. Step 4: Start the threads. For producer thread, use produce() and for consumer, consume(). Step 5: Wait for all the threads to complete. Step 6: Print the number of items produced by each producer thread. Step 7: Print the number of items consumed by each consumer thread. Step 8: Print the number of items remaining in the buffer. T90
In the produce() function, do: Step 1: Lock the mutex for the buffer. Step 2: If the buffer has reached the limit, unlock and stop. Step 3: Else, write to the next location in the buffer, and increment the location counter. Step 4: Increment p_count[i] for that thread, and unlock. T90
In the consume() function, do: Step 1: Lock the mutex. Step 2: Check for the first written location. Step 3: If it is the end of buffer, unlock and stop. Else, read the item and set that location to EMPTY. Step 4: Increment c_count[i] for that thread, and unlock. T90
Important Functions Used • sem_init • sem_post • sem_wait • sem_destroy • pthread_create T90
sem_init • sem_init() • Initialize an unnamed semaphore • Synopsis: #include <semaphore.h> intsem_init( sem_t * sem, intpshared, unsigned value ); T90
Sem • A pointer to the sem_t object for the semaphore that you want to initialize. • pshared • Nonzero if you want the semaphore to be shared between processes via shared memory. • value • The initial value of the semaphore. A positive value (i.e. greater than zero) indicates an unlocked semaphore, and a value of 0 (zero) indicates a locked semaphore. This value must not exceed SEM_VALUE_MAX. T90
Library: • libc • Use the -l c option to gcc to link against this library. • This library is usually included automatically. T90
You can use the initialized semaphore in subsequent calls to sem_wait(), sem_trywait(), sem_post(), and sem_destroy(). • An initialized semaphore is valid until it's destroyed by the sem_destroy() function, or until the memory where the semaphore resides is released. • If the pshared argument is nonzero, then the semaphore can be shared between processes via shared memory. • Any process can then use sem with the sem_wait(), sem_trywait(), sem_post() and sem_destroy() functions. T90
Return Value • 0 • Success. • The semaphore referred to by sem is initialized. • -1 • An error occurred (errno is set). T90
sem_post() • Increment a named or unnamed semaphore • Synopsis : #include <semaphore.h> int sem_post( sem_t * sem ); • sem • A pointer to the sem_t object for the semaphore whose value you want to increment. T90
The sem_post() function increments the semaphore referenced by the sem argument. If any processes are currently blocked waiting for the semaphore, then one of these processes will return successfully from its call to sem_wait. • The process to be unblocked is determined in accordance with the scheduling policies in effect for the blocked processes. The highest priority waiting process is unblocked, and if there is more than one highest priority process blocked waiting for the semaphore, then the highest priority process that has been waiting the longest is unblocked. • The sem_post() function is reentrant with respect to signals, and can be called from a signal handler. T90
Return Value • 0 • Success. • -1 • An error occurred (errno is set). T90
sem_wait() • Wait on a named or unnamed semaphore Synopsis: #include <semaphore.h> intsem_wait( sem_t * sem); • sem • A pointer to the sem_t object for the semaphore that you want to wait on. T90
The sem_wait() function decrements the semaphore referred to by the sem argument. If the semaphore value is not greater than zero, then the calling process blocks until it can decrement the counter, or the call is interrupted by signal. • Some process should eventually call sem_post() to increment the semaphore. T90
Return Value • 0 • The semaphore was successfully decremented. • -1 • The state of the semaphore is unchanged (errno is set). T90
sem_destroy() • Destroy a semaphore Synopsis: #include <semaphore.h> intsem_destroy( sem_t * sem); • sem • A pointer to the sem_t object for the semaphore that you want to destroy. T90
The sem_destroy() function destroys the unnamed semaphore referred to by the sem argument. The semaphore must have been previously initialized by the sem_init() function. • The effect of using a semaphore after it has been destroyed is undefined. If you destroy a semaphore that other processes are currently blocked on, they're unblocked, with an error (EINVAL). T90
Return Value • 0 • Success. • -1 • An error occurred (errno is set). T90