Reputation: 587
I want write a program producer/consumer, in this program I have a parent and a son, the parent fills a shared variable with a number of fish and it send notify at son. The son start eating, if there are not fish, it notify parent. I tried this code, but it not working:
import threading
import time
NUM_FISH = 13
mutex = threading.Lock()
mutParent = threading.Event()
mutSon = threading.Event()
fish = NUM_FISH
def set(fish1):
global fish
fish = fish1
def get():
return fish
def parent(mutParent, mutSon):
while True:
mutex.acquire()
mutParent.wait()
time.sleep(0.5)
try:
set(NUM_FISH)
print " + parent brings %d fish\n" % fish
mutex.release()
mutSon.set()
except:
print "Exception"
mutex.release()
def son(id, mutParent, mutSon):
while True:
mutex.acquire()
mutSon.wait()
fish = get() - 1
set(fish)
time.sleep(0.5)
try:
if fish > 0 :
print " - Son %d eats (dish: %d fish)\n" % (id, fish)
mutex.release()
else:
print " - Son %d eats (dish: %d fish) and screams\n\n" % (id, fish)
mutex.release()
mutParent.set()
except:
print "Exception"
mutex.release()
print "\n + intitial dish: %d fish\n\n" % fish
mutSon.set()
t2 = threading.Thread(target=son, args=(1, mutParent, mutSon))
t2.start()
t1 = threading.Thread(target=parent, args = (mutParent, mutSon))
t1.start()
t2.join()
t1.join()
This is my output:
myself@ubuntu:~/Desktop$ python a.py
+ intitial dish: 13 fish
- Son 1 eats (dish: 12 fish)
- Son 1 eats (dish: 11 fish)
- Son 1 eats (dish: 10 fish)
- Son 1 eats (dish: 9 fish)
- Son 1 eats (dish: 8 fish)
- Son 1 eats (dish: 7 fish)
- Son 1 eats (dish: 6 fish)
- Son 1 eats (dish: 5 fish)
- Son 1 eats (dish: 4 fish)
- Son 1 eats (dish: 3 fish)
- Son 1 eats (dish: 2 fish)
- Son 1 eats (dish: 1 fish)
- Son 1 eats (dish: 0 fish) and screams
- Son 1 eats (dish: -1 fish) and screams
- Son 1 eats (dish: -2 fish) and screams
- Son 1 eats (dish: -3 fish) and screams
- Son 1 eats (dish: -4 fish) and screams
- Son 1 eats (dish: -5 fish) and screams
+ parent brings 13 fish
+ parent brings 13 fish
Upvotes: 3
Views: 129
Reputation: 5844
OK, there are three things here that can be changed:
with mutex:
instead of all the mutex.acquire()
and mutex.release()
, as then that stuff happens automatically, making the code shorter and less error prone.mutex
. Otherwise a thread will acquire the mutex, then begin to wait for its condition variable, however, the tread that is supposed to set it can't acquire mutex
, so everything stops. Note that, when there is multiple sons or parents, the event has to be rechecked after locking mutex
. This is because after waiting for the event, the event may be cleared before mutex
has been acquired.Making those adjustments gives me this code:
def parent(id, mutParent, mutSon):
while True:
mutParent.wait()
with mutex:
if not mutParent.is_set():
continue
time.sleep(0.5)
try:
set(NUM_FISH)
print " + Parent %d brings %d fish\n" % (id, fish)
mutParent.clear()
mutSon.set()
except:
print "Exception"
def son(id, mutParent, mutSon):
while True:
mutSon.wait()
with mutex:
if not mutSon.is_set():
continue
fish = get() - 1
set(fish)
time.sleep(0.5)
try:
if fish > 0:
print " - Son %d eats (dish: %d fish)\n" % (id, fish)
else:
print " - Son %d eats (dish: %d fish) and screams\n\n" % (id, fish)
mutSon.clear()
mutParent.set()
except:
print "Exception"
I haven't managed to break this (works with multiple sons or parents), so I think its correct, but any correction on this point is most welcome (as this is multithreading, and weird things lie in the shadows of parallelism).
Upvotes: 4