[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.python

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

Matthew Wilson

1/19/2008 12:43:00 AM

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
6 Answers

Carl Banks

1/19/2008 1:26:00 AM

0

On Jan 18, 7:43 pm, Matthew Wilson <m...@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()


It looks like your program's hanging while the waiter is waits to
acquire another plate of hot food.

Quick and dirty solution is to have waiter timeout at intervals while
waiting for the chef and check the clock to see if his shift has
ended. Better solution is to rewrite the logic, which you did.


Carl Banks

Sergio Correia

1/19/2008 1:38:00 AM

0

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@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/p...
>

nir1408

1/20/2008 1:30:00 PM

0

On Jan 19, 2:43 am, Matthew Wilson <m...@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

It does not check a different variable.
You can open a Python session and try the following:

Python 2.5.1 (r251:54863, Oct 5 2007, 13:36:32)
[GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = True
>>> id(a)
135527852
>>> a = False
>>> id(a)
135527840

The problem is that the waiter is locked waiting for new food and
never looks at the variable.
You should add hot_food.release() after you set the keep running flag
to False.

Nir

Tim Roberts

1/22/2008 6:04:00 AM

0

Matthew Wilson <matt@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.
>...
>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.

You misunderstand what "id(a)" does. "id" doesn't tell you anything about
the name "a" or the address of "a". What it tells you is the unique
identifier of the object that "a" is bound to. Any time you change "a",
"id(a)" will also change.

Note, for example:

C:\tmp>python
Python 2.4.4 (#71, Oct 18 2006, 08:34:43) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> id(True)
504958236
>>> a = True
>>> id(a)
504958236

>>> id(False)
504958224
>>> a = False
>>> b = False
>>> id(a)
504958224
>>> id(b)
504958224
>>>

504958236 is the id of "True", not of "a".
--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Dave Kelly

7/6/2011 1:47:00 AM

0


"iL_WeReo" <caljamscott@yahoo.com> hallucinated in message .

> Awesome! I'd like to do it bathed in nitroglycerin.
> It's not that hard to make, ya know. In fact it's pretty easy.

That would work too...anything that will engulf you
(and that 8-track tape of the lame 1974 Deep Purple concert)
in flames will do the trick....gas soaked rags...molotov cocktails.....
maybe you could rent a flame thrower and turn it on yourself?
Doing it in front of Ian Gillans house is the icing on the cake.
You let us know if you need any help, K?


iL_WeReo

7/7/2011 2:47:00 AM

0

On Jul 5, 9:46 pm, "sweetbac" <sweet...@sbcglobal.net> wrote:
> "iL_WeReo" <caljamsc...@yahoo.com> hallucinated in message .
>
> > Awesome! I'd like to do it bathed in nitroglycerin.
> > It's not that hard to make, ya know. In fact it's pretty easy.
>
> That would work too...anything that will engulf you
> (and that 8-track tape of the lame 1974 Deep Purple concert)
> in flames will do the trick....gas soaked rags...molotov cocktails.....
> maybe you could rent a flame thrower and turn it on yourself?
> Doing it in front of Ian Gillans house is the icing on the cake.
> You let us know if you need any help, K?

Leave me alone, please?