Condition.wait(timeout) oddities

Floris Bruynooghe floris.bruynooghe at gmail.com
Mon May 23 17:43:19 EDT 2011


On Monday, 23 May 2011 17:32:19 UTC, Chris Torek  wrote:
> In article
> <94d1d127-b423-4bd4... at glegroupsg2000goo.googlegroups.com>
> Floris Bruynooghe  <comp.lan... at googlegroups.com> wrote:
> >I'm a little confused about the corner cases of Condition.wait() with a
> >timeout parameter in the threading module.
> >
> >When looking at the code the first thing that I don't quite get is that
> >the timeout should never work as far as I understand it.  .wait() always
> >needs to return while holding the lock, therefore it does an .acquire()
> >on the lock in a finally clause.  Thus pretty much ignoring the timeout
> >value.
> 
> It does not do a straight acquire, it uses self._acquire_restore(),
> which for a condition variable, does instead:
> 
>         self.__block.acquire()
>         self.__count = count
>         self.__owner = owner
> 
> (assuming that you did not override the lock argument or passed
> in a threading.RLock() object as the lock), due to this bit of
> code in _Condition.__init__():
> 
>         # If the lock defines _release_save() and/or _acquire_restore(),
>         # these override the default implementations (which just call
>         # release() and acquire() on the lock).  Ditto for _is_owned().
>         [snippage]
>         try:
>             self._acquire_restore = lock._acquire_restore
>         except AttributeError:
>             pass

Ah, I missed this bit in the __init__() and the fact that RLock provides the _acquire_restore() and _release_save().  I was wondering why they jumped around via self._acquire_restore() and self._release_save(), it seemed rather a lot of undocumented effort for custom locks.


> That is, lock it holds is the one on the "blocking lock" (the
> __block of the underlying RLock), which is the same one you had
> to hold in the first place to call the .wait() function.
> 
> To put it another way, the lock that .wait() waits for is
> a new lock allocated for the duration of the .wait() operation:

That makes more sense now.  I knew that really, just never quite realised until you wrote this here so clearly.  Thanks.

So essentially the condition's lock is only meant to lock the internal state of the condition and not meant to be acquired for long times outside that as .wait() calls will not be able to return.  My confusion started from looking at queue.Queue which replaces the lock with a regular lock and uses it to lock the Queue's resource.  I guess the Queue's mutex satisfies the requirement of never being held for long times.


> >The second issue is that while looking around for this I found two bug
> >reports: http://bugs.python.org/issue1175933 and
> >http://bugs.python.org/issue10218.  Both are proposing to add a return
> >value indicating whether the .wait() timed out or not similar to the
> >other .wait() methods in threading.  However the first was rejected
> >after some (seemingly inconclusive) discussion.
> 
> Tim Peters' reply seemed pretty conclusive to me. :-)

Which is why I'm surprised that it now does.


Cheers
Floris



More information about the Python-list mailing list