Condition.wait(0.5) doesn't respect it's timeout

Piet van Oostrum piet at cs.uu.nl
Sat Apr 18 05:24:03 EDT 2009


>>>>> stephane.bisinger at gmail.com (SB) wrote:

>SB> Hi all,
>SB> I have a problem with Condition.wait(), it doesn't return after the
>SB> given timeout. The thing is that if I try to create a simple program,
>SB> it works as expected, but in the actual code, the timeout is not
>SB> respected (albeit the notify()s work as expected).
>SB> You can find the code I am talking about here:
>SB> http://github.com/Kjir/amsn2/blob/6688da4c0b7cc16c0fe04d6d6018bc1b16d992a6/amsn2/gui/front_ends/curses/contact_list.py

>SB> If you clone the repository, then you can run the program like this:
>SB> $ python amsn2.py -f curses 2>> run.log
>SB> and in another term watch for prints with a tail -f run.log (You need
>SB> an MSN account). You'll notice that after the initial downloading of
>SB> the contact list, there won't be any logs (unless some of your
>SB> contacts changes status, which will trigger a notify)

>SB> Has anyone the slightest idea on what I may be doing wrong? Or am I
>SB> just lucky enough to have stumbled across a bug? Maybe pollution from
>SB> another module in other parts of the code? (Like gobject...)

I haven't run it (too much hassle to setup) but I noticed one strange
thing in your code:

,----
| def groupUpdated(self, gView):
|         # Acquire the lock to do modifications
|         self._mod_lock.acquire()
|  
|         if not self._groups.has_key(gView.uid):
|             return
`----

In case the return is taken, the lock will not be released thereby
blocking the rest. It could be that the timeout is taken, but before the
wait can continue it has to acquire the lock again.

It is best to put all your code after the acquire in a try: finally:
like 

,----
| self._mod_lock.acquire()
| try:
|         do something
| finally:
|         self._mod_lock.release()
`----

or even better use the with statement:

,----
| with self._mod_lock:
|      do something
`----
It will do the releasing automatically

And then something else:
,----
| def __thread_run(self):
|        while True:
|            import sys
|            print >> sys.stderr, "at loop start"
|            self._mod_lock.acquire()
|            t = time.time()
|            # We don't want to work before at least half a second has passed
|            while time.time() - t < 0.5 or not self._modified:
|                print >> sys.stderr, "Going to sleep\n"
|                self._mod_lock.wait(timeout=1)
|                print >> sys.stderr, "Ok time to see if we must repaint"
|            self.__repaint()
|            t = time.time()
|            self._mod_lock.release()
|            print >> sys.stderr, "at loop end"
|            self._mod_lock.acquire()
`----

Your loop ends with self._mod_lock.acquire() but in the next round there
is another self._mod_lock.acquire() at the beginning of the loop. So the
acquire at the end isn't necessary.

-- 
Piet van Oostrum <piet at cs.uu.nl>
URL: http://pietvanoostrum.com [PGP 8DAE142BE17999C4]
Private email: piet at vanoostrum.org



More information about the Python-list mailing list