Concurrency pattern: Producer-consumer |
Written by Mottola Michele - Italy - Reggio Emilia |
Monday, 07 September 2015 09:39 |
Last Updated on Tuesday, 08 September 2015 18:39 |
What is the problemBasically this pattern solve the problem of a buffer, in which one or more Producer can push a data and one or more Consumer can pull a data. There are a couple of problems that can arise: the first is catch to ’race condition’, indeed since to the buffer can access more productors and consumers at the same time, can arise problems of inconsistency data. The second problem is catch to ’deadlock’, mean a lock of system. How this pattern workIn this pattern, the problem of ’race condition’ arise, for example, if we allow to do, at the same time, push and pull operation. In this case, since both methos changes the internal state of the buffer object, they can read not right data. Generally to avoid ’race condition’ problems on an obbject it’s enough use the ’single threaded execution’ pattern. Single threaded executionBasically, in our case, the ’single threaded execution’ allows to the methos of object of type Buffer, signed as ’guarded’, may be executed by only one thread at same time. The thread that may use a method signed ’guarded’ obtain the lock of buffer’s object and it release the lock only after has finished the call. DeadlockThere is still the problem of deadlock. If we modelling the behaviour of this system with only two tread, one for the producer and one for the consumer, using only the ’single threaded execution’ we have an activity diagram like this:
From this we can understand how work the consumer thread. It first checks the availability of lock, if it is free it obtain, instead if it is busy it go in queue and wait until is free. Then it checks if there are data in buffer, if there are it pull it, finish its execution and release the lock. But what happen if there aren’t data on buffer? It wait until the buffer get push from the producer. But the thread of producer may not obtain the lock because it is keep from the thread of consumer. So there is a deadlock. Class diagramJava implementationThe java implementation is very quick. Basically we need to implement push() and pull() methods in Buffer. It’s to notice that in java, a method signed as ’guarded’ is implemented using the keyword ’synchronized’. Besides the notification system between the thread, in java is implemented by wait() and notify() methods. Buffer.javaProducer.javaConsumer.javaTo simulate the behaviour of this system we can use java thread. So we need one thread to simulate the behavour of Producer and one for the Consumer. The test i show here is to show how the thread of consumer work when the buffer is empty. The consumer thread will wait until the producer doesn’t push a data in buffer. Only then the consumer will continue it’s execution fetching a data from buffer. Test.javaOutput
When i run the program, the thread of consumer start, instead the thread of producer will wait until i press a button. This will be the message |