0

I have simple producer, consumer problem. While producer thread adding 10$ to global money variable, consumer thread will spend money. But there is one condition that money cannot be under 0. The example code given below:

from threading import Thread, Condition

condition = Condition()
money = 0

def producer():
    global money
    for _ in range(1000000):
        condition.acquire()
        money += 10
        condition.notify()
        condition.release()

def consumer():
    global money
    for _ in range(500000):
        condition.acquire()
        if money < 0:
        # while money < 0: why it's needed ? 
            condition.wait()
        money -= 20
        print("money in the bank after spend => ", money)
        condition.release()
        

if __name__ == "__main__":
 
    t1 = Thread(target=producer, args=())
    t2 = Thread(target=consumer, args=())

    t1.start()
    t2.start()

    t1.join()
    t2.join()

I saw many examples and they are using while money < 20: instead of my if control and I am confused right there. When thread waits with condition.wait() simply it release the condition lock and when consumer consume 10$ then notify the producer thread, the producer function starts working with acquiring the condition lock first. So there is no make sense to use while loop over there. Because every time the thread notifies, first step the notified thread try to acquire the lock and rest of the code continues working as normal flow. So there is no need to use while loop to control money variable's instant change, it will control the money variable anyways if the program running as expected. Am I right ? Or am I missing some point ?

1 Answer 1

1

The reason for using a while loop is hinted at in the documentation:

The while loop checking for the application’s condition is necessary because wait() can return after an arbitrary long time, and the condition which prompted the notify() call may no longer hold true.

If you think about your code with an if-condition:

with condition:
    if money < 0:
        condition.wait()
    money -= 20

... it is possible (at least as far as the implementation of the condition variable is concerned) that

  1. condition gets locked
  2. money is smaller than 0
  3. We condition.wait(); the lock is unlocked and "something" happens elsewhere
  4. "something" notifies all threads waiting on condition.
  5. Some other thread acquires the lock on condition and executes, modifying money, then unlocks condition
  6. Our thread returns from .wait() after acquiring the lock
  7. While the condition we waited for had become true while we hadn't acquired the lock, it also became untrue while we hadn't acquired the lock. We were notified about "a change" in the condition. But when we get around to inspect it, it is no longer true.

While your code in particular may not be susceptible to this problem, it is generally good code hygiene // muscle memory to design your code in such a way that it does not suffer from the problem described above: While .wait() executes, your thread might get notified, but the condition you are waiting for is no longer true by the time wait() returns.

The while-loop makes sure that if the condition became true and untrue while the lock was released, we simple try again.

Sign up to request clarification or add additional context in comments.

2 Comments

Can you plz answer that question. Where does the notified thread start to work again from ? Does it start to work from where condition.wait() is located or from where condition.acquire() lock captured ? I can understand all of that you wrote above according to your answer of that question.
The notified thread acquires the lock, so no other thread can notify (because they themselves need to acquire the lock); the notified thread then checks the condition, and if its untrue, waits for it; wait then releases the lock so other threads can make progress; the notified thread re-acquires the lock and "starts to work again" when returning from wait(); in then checks if the condition has indeed become true <- this is why we use a while-loop

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.