I have an object instance that holds two queues, an input queue and an output queue. The parent process spawns several child processes that work on the queues.
My requirements are:
- it should be possible to fill the input queue at any time (function
fill()
in the code below) - the child processes should process items from the input queue. If the input queue is empty, they should wait for the input queue to be filled (function
echo()
) - items should be read from the output queue if it is not empty (function
read()
) - if a shared shutdown flag (attribute
self._shutdown
) is set to true, all processes should end instead of waiting for queue items
Here is the code I currently have:
Python 2.7 Minimal Example
from multiprocessing import Queue, Process, Value
from ctypes import c_bool
from Queue import Empty
class A(object):
def __init__(self):
self._shutdown = Value(c_bool, False)
self._input_queue = Queue()
self._output_queue = Queue()
def echo(self):
while True:
if self._shutdown.value == True: break
try:
item = self._input_queue.get(True, timeout=1)
except Empty:
continue
print "[echo] read from input qeue: ", item
print "[echo] put into output queue: ", item*2
self._output_queue.put(item*2)
def fill(self):
for item in xrange(1,6):
print "[fill] put into input queue: ", item
self._input_queue.put(item)
def read(self):
while True:
if self._shutdown.value == True: break
try:
item = self._output_queue.get(True, timeout=1)
except Empty:
continue
print "[read] got from output queue: ", item
a = A()
p1 = Process(target=a.echo)
p2 = Process(target=a.echo)
p1.start()
p2.start()
a.fill()
a.read()
a._shutdown.value = True
The output of the script above is correct:
[fill] put into input queue: 1
[fill] put into input queue: 2
[fill] put into input queue: 3
[fill] put into input queue: 4
[fill] put into input queue: 5
[echo] read from input qeue: 1
[echo] put into output queue: 2
[echo] read from input qeue: 2
[echo] put into output queue: 4
[echo] read from input qeue: 3
[echo] put into output queue: 6
[read] got from output queue: 2
[echo] read from input qeue: 4
[read] got from output queue: 6
[echo] put into output queue: 8
[echo] read from input qeue: 5
[echo] put into output queue: 10
[read] got from output queue: 8
[read] got from output queue: 4
[read] got from output queue: 10
Except that it deadlocks and the process never finishes. It seems that the processes block each other. My question is:
Why exactly does my code deadlock and what can I do to prevent this?