Home > OS >  Two threads kept running without completing
Two threads kept running without completing

Time:11-29

I'm trying to get the result below running 2 threads alternately. *Thread A prints Step 1 and Step 3 and thread B prints Step 2 and Step 4 (I use Python 3.8.5):

Step 1
Step 2
Step 3
Step 4

So, with global variables, locks and while statements, I created the code below to try to get the result above:

import threading
lock = threading.Lock()

flow = "Step 1"

def test1():
    global flow
    while True:
        while True:
            if flow == "Step 1":
                lock.acquire()
                print(flow)
                flow = "Step 2"
                lock.release()
                break
        
        while True:
            if flow == "Step 3":
                lock.acquire()
                print(flow)
                flow = "Step 4"
                lock.release()
                break
            break

def test2():
    global flow
    while True:
        while True:
            if flow == "Step 2":
                lock.acquire()
                print(flow)
                flow = "Step 3"
                lock.release()
                break
        
        while True:
            if flow == "Step 4":
                lock.acquire()
                print(flow)
                lock.release()
                break
            break

t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)

t1.start()
t2.start()

t1.join()
t2.join()

But, the code above got the result below without Step 3 and Step 4, then the program kept running without completed. *Thread A printed Step 1, then thread B printed Step 2, then the program kept running without printing Step 3 and Step 4:

Step 1
Step 2

I couldn't find any mistakes so how can I get the proper result with Step 3 and Step 4? And, why did I get the result without Step 3 and Step 4?

CodePudding user response:

In both second while loops you have an extra break that terminates the execution after first run. (outside the if-block). And you have also souperflous extra outside-while loops.


def test1():
    global flow
    while True: # <--- DELETE ME
        while True:
            if flow == "Step 1":
                lock.acquire()
                print(flow)
                flow = "Step 2"
                lock.release()
                break
        
        while True:
            if flow == "Step 3":
                lock.acquire()
                print(flow)
                flow = "Step 4"
                lock.release()
                break
            break # <--- DELETE ME

However, you are reading the flow outside of the lock state. In an real world application this could case an error, as the variable can change between the if and the lock. Thus, this code is NOT really THREADSAFE even with the lock.

CodePudding user response:

The position of each last break in test1() and test2() is wrong so you need to put each last break just in the outer while statement as shown below:

import threading
lock = threading.Lock()

flow = "Step 1"

def test1():
    global flow
    while True:
        while True:
            if flow == "Step 1":
                lock.acquire()
                print(flow)
                flow = "Step 2"
                lock.release()
                break
        
        while True:
            if flow == "Step 3":
                lock.acquire()
                print(flow)
                flow = "Step 4"
                lock.release()
                break
        break # This breaks the outer "while" statement

def test2():
    global flow
    while True:
        while True:
            if flow == "Step 2":
                lock.acquire()
                print(flow)
                flow = "Step 3"
                lock.release()
                break
        
        while True:
            if flow == "Step 4":
                lock.acquire()
                print(flow)
                lock.release()
                break
        break # # This breaks the outer "while" statement

t1 = threading.Thread(target=test1)
t2 = threading.Thread(target=test2)

t1.start()
t2.start()

t1.join()
t2.join()

Then, you can get the proper result below:

Step 1
Step 2
Step 3
Step 4
  • Related