luke_16
luke_16

Reputation: 187

Synchronizing 2 threads in python

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

Answers (2)

luke_16
luke_16

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

a_guest
a_guest

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:

  • Remove the comma after print (which will cause every letter to be printed in a separate line).
  • Or if you wish to write them to the same line you can use sys.stdout.write('A/B ') followed by sys.stdout.flush() (to keep the output updated). Don't forget to import sys.

Upvotes: 2

Related Questions