I don't understand what is happening in this threading code

Sergio Correia sergio.correia at gmail.com
Fri Jan 18 20:38:24 EST 2008


This is what's happening:

 1) The chef thread releases the sema
 2) While the chef thread is saying "Andiamo", decreasing "i", and
ending the while loop, the waiter thread SERVES the dish and RUNS to
reacquire the lock
 3) Back in the main loop, chef.join() is run, and then the waiter's
variable is changed.

But it's already too late. The waiter is already locked. He'll wait
and wait forever for another dish, which will never come. So you will
have to kill him. All for a race condition.

---
I've just read Carl's post (just b4 hitting submit).

I agree with him, rewrite the logic. IMO, the objects should be the
key, THEY are the ones that should be joined. You should run the chef
and waiter as daemons, and just do something like

orders.join()
dishes.join()

And when the chefs finishes with the orders and the waiter finishes
serving them, the program ends.

HTH,
Sergio


On Jan 18, 2008 7:43 PM, Matthew Wilson <matt at tplus1.com> wrote:
> In this code, I tried to kill my thread object by setting a variable on it
> to False.
>
> Inside the run method of my thread object, it checks a different
> variable.
>
> I've already rewritten this code to use semaphores, but I'm just curious
> what is going on.
>
> Here's the code:
>
> import logging, threading, time
> logging.basicConfig(level=logging.DEBUG,
>                     format="%(threadName)s: %(message)s")
>
> class Waiter(threading.Thread):
>     def __init__(self, hot_food):
>         super(Waiter, self).__init__()
>         self.should_keep_running = True
>         self.hot_food = hot_food
>
>     def run(self):
>         while self.should_keep_running:
>             logging.debug("Inside run, the id of should_keep_running is %s."
>                           % id(self.should_keep_running))
>             self.hot_food.acquire()
>
> def cook_food(hot_food):
>     i = 5
>     while i >= 0:
>         logging.debug("I am cooking food...")
>         time.sleep(1)
>         hot_food.release()
>         logging.debug("Andiamo!")
>         i -= 1
>
> def main():
>
>     hot_food = threading.Semaphore(value=0)
>
>     chef = threading.Thread(name="chef", target=cook_food, args=(hot_food, ))
>     chef.start()
>
>     w = Waiter(hot_food)
>     logging.debug("Initially, the id of w.should_keep_running is %s."
>               % id(w.should_keep_running))
>     w.start()
>     logging.debug("After start, the id of w.should_keep_running is %s."
>               % id(w.should_keep_running))
>
>     # Wait for the chef to finish work.
>     chef.join()
>
>     # Now try to kill off the waiter by setting a variable inside the waiter.
>     w.should_keep_running = False
>     logging.debug("Now, the id of w.should_keep_running is %s."
>                   % id(w.should_keep_running))
>
> if __name__ == "__main__":
>     main()
>
> And here's what I get when I execute it.  I have to suspend the process
> with CTRL=Z and then kill -9 it.
>
> $ python foo.py
> MainThread: Initially, the id of w.should_keep_running is 135527852.
> MainThread: After start, the id of w.should_keep_running is 135527852.
> chef: I am cooking food...
> Thread-1: Inside run, the id of should_keep_running is 135527852.
> chef: Andiamo!
> chef: I am cooking food...
> Thread-1: Inside run, the id of should_keep_running is 135527852.
> chef: Andiamo!
> chef: I am cooking food...
> Thread-1: Inside run, the id of should_keep_running is 135527852.
> chef: Andiamo!
> chef: I am cooking food...
> Thread-1: Inside run, the id of should_keep_running is 135527852.
> chef: Andiamo!
> chef: I am cooking food...
> Thread-1: Inside run, the id of should_keep_running is 135527852.
> chef: Andiamo!
> chef: I am cooking food...
> Thread-1: Inside run, the id of should_keep_running is 135527852.
> chef: Andiamo!
> Thread-1: Inside run, the id of should_keep_running is 135527852.
> MainThread: Now, the id of w.should_keep_running is 135527840.
>
> [1]+  Stopped                 python foo.py
>
> $ kill -9 %1
>
> [1]+  Stopped                 python foo.py
>
> The memory address of should_keep_running seems to change when I set it
> from True to False, and inside the run method, I keep checking the old
> location.
>
> I am totally baffled what this means.
>
> Like I said earlier, I already rewrote this code to use semaphores, but
> I just want to know what is going on here.
>
> Any explanation is welcome.
>
> TIA
>
> Matt
> --
> http://mail.python.org/mailman/listinfo/python-list
>



More information about the Python-list mailing list