import threading
import time
money_flag=threading.Lock()
balance = 0
nb_transaction = 999999
counter = 0
def transaction(nb_transaction, n):
global balance
global counter
for _ in range(nb_transaction):
if balance < 0:
counter += 1
money_flag.acquire()
balance += n
money_flag.release()
t1 = threading.Thread(target=transaction, args=(nb_transaction,1,))
t2 = threading.Thread(target=transaction, args=(nb_transaction,-1,))
t1.start()
t2.start()
t1.join()
t2.join()
print(counter)
print(balance)
In the above code, the balance can go below zero occasionally. To prevent it from being less than zero, I add a money_flag, but this does not help. How to make sure that the thread 2 function pauses when the balance is less than 0? At the end, the expected balance should be zero.
You should be using a condition variable, not a lock.
cv = threading.Condition()
def transaction(nb_transaction, n):
global balance
for _ in range(nb_transaction):
with cv:
cv.wait_for(lambda: balance + n >= 0)
balance += n
cv.notify_all()
The cv.wait_for()
ensures than when it returns, balance + n >= 0
is true and that it still holds the lock that it had when it tested that condition.
The cv.notify_all()
(it could probably be just cv.notify() here, but in general
notify_all()` is safer) says that "things have changed" and that anyone waiting should try again.