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