Reputation: 187
I am having great difficulty in synchronising 2 Threads. Each thread depends on the results of the other thread. Let's say I have the following code:
from multiprocessing import Condition, Process
import time
def B_producer(new_A,new_B):
while True:
with new_A:
new_A.wait()
with new_B:
print 'B',
new_B.notify_all()
if __name__=='__main__':
new_A = Condition()
new_B = Condition()
B_producer = Process(target=B_producer, args=(new_A,new_B))
B_producer.start()
time.sleep(2)
while True:
with new_A:
print 'A',
new_A.notify()
with new_B:
new_B.wait()
What I would like to see is an output like: A B A B A B A B A B..., so that the main thread starts by generating an 'A', while the other is waiting. Once an 'A' has been produced, it waits for the 'B'. Meanwhile, the secondary thread do the opposite. There can be no repetition of letters. Unfortunately, I cannot find a way to make it work as expected.
EDIT: Given the discussion in the first answer, I altered the code in order to make it more clear that the program enters in a deadlock and never terminates:
from multiprocessing import Condition, Process
import time
def B_producer(new_A,new_B):
while True:
with new_A:
new_A.wait()
with new_B:
#do something
new_B.notify_all()
if __name__=='__main__':
new_A = Condition()
new_B = Condition()
B_producer = Process(target=B_producer, args=(new_A,new_B))
B_producer.start()
time.sleep(2)
count = 0
while True:
with new_A:
#do something
new_A.notify()
with new_B:
new_B.wait()
count += 1
if count == 1000000:
break
B_producer.terminate()
sys.stdout.write('end')
sys.stdout.flush()
Upvotes: 1
Views: 82
Reputation: 187
I think I got a solution for it, even though there may be a simpler one. I added a start condition to it in order to avoid the main loop from starting before the B_producer is ready and waiting for the main thread to do its part. I also had to add an additional Lock to prevent a race condition to the new_A condition.
def B_producer(new_A,new_B,synch,start):
synch.acquire()
while True:
with new_A:
synch.release()
with start:
start.notify()
new_A.wait()
with new_B:
#Do something
synch.acquire()
new_B.notify()
if __name__=='__main__':
new_A = Condition()
new_B = Condition()
start = Condition()
synch = Lock()
B_producer = Process(target=B_producer, args=(new_A,new_B,synch,start))
with start:
B_producer.start()
start.wait()
count = 0
synch.acquire()
while True:
new_A.acquire()
synch.release()
#Do something
with new_B:
new_A.notify()
new_A.release()
new_B.wait()
synch.acquire()
count += 1
if count%100000 == 0:
break
B_producer.terminate()
print 'end'
If anybody finds a better/simpler solution, please post it!
Thanks
Upvotes: 0
Reputation: 36269
Your code works, the only thing is you experience some issues with print "A/B",
. The problem here is the comma after print
. It prevents a line break after printing but the print statement is not able to update an already written line on the console but only to write single lines. Therefore it stores everything in a buffer until you perform a print
with linebreak and then the whole line is written.
You can do two things:
print
(which will cause every letter to be printed in a separate line).sys.stdout.write('A/B ')
followed by sys.stdout.flush()
(to keep the output updated). Don't forget to import sys
.Upvotes: 2