[Patches] [ python-Patches-1175933 ] threading.Condition.wait() return value indicates timeout

SourceForge.net noreply at sourceforge.net
Sat Apr 30 16:03:59 CEST 2005


Patches item #1175933, was opened at 2005-04-03 19:09
Message generated for change (Comment added) made by blais
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1175933&group_id=5470

Category: Library (Lib)
Group: Python 2.4
Status: Open
Resolution: None
Priority: 5
Submitted By: Martin Blais (blais)
Assigned to: Nobody/Anonymous (nobody)
Summary: threading.Condition.wait() return value indicates timeout

Initial Comment:
A condition variable returns in two cases: it was
notified by another thread, or it timed out (if a
timeout was specified).  See an example in the popular
Boost C++ library:

http://boost.org/doc/html/condition.html

This patch adds this capability to the Python
threading.Condition.wait() method, which used to return
nothing.  I added the relevant couple of lines to the
documentaion as well (see patch).

(An example is using a condition variable as a sentinel
for exiting a loop or a polling thread.  Using the
return value one can decide whether to exit the loop or
not.)


----------------------------------------------------------------------

>Comment By: Martin Blais (blais)
Date: 2005-04-30 14:03

Message:
Logged In: YES 
user_id=10996

hi tim
thanks for the comments.

my use of a condition variable is exemplified in this
background thread, which computes something periodically,
and with which the main thread uses a condition variable to
communicate "pause" and "quit" states (there is
communication between only those two threads):

def background_thread( func, args, condvar, callbacks, delay ):
    """
    A background thread that computes something periodically.

    @func: function that computes something;
    @data: arguments for function that computes something;
    @condvar: a variable to indicate for the thread to stop
or pause.
              The variable is the 'pause' and 'quit' members
on the condvar.
    @callbacks: a list of functions to call when a new
result becomes available;
    """
    done = 0
    while not done:
        # compute something
        data = func(*args)
        
        # push the new data into the callbacks
        for cb in callbacks:
            cb(data)

        condvar.acquire()
        if condvar.pause:
            # this branch is used to pause the thread.
            condvar.wait()
        else:
            condvar.wait(delay)
        if condvar.quit:
            done = 1
        condvar.release()

instead of using the "quit" data member, i could instead use
the return value of the wait() call.  basically, exit the
loop when i've been signaled.

AFAIK this is a common usage pattern. i've seen it in a few
places.  do you see any problem with this usage?

not that it's really an argument, but i did see 3
independent implementations of wait() returning the
signaled/timeout boolean.

i think Event.wait() should also return the signaled/timeout
state.  it's information that should be returned to the
user, whether he uses it or not.  sure, people can screw up,
but if there is a legitimate case where it can be used, i
think it should be provided anyway.

also, you are correct about mdehoon's case, after returning
from wait(), one should check for the queue being empty or not.



----------------------------------------------------------------------

Comment By: Tim Peters (tim_one)
Date: 2005-04-30 04:39

Message:
Logged In: YES 
user_id=31435

Sorry, I think this is a poor idea, and mdehoon's suggestion 
for turning a correct use of .wait() into a doubly buggy one 
illustrates why:  there's no guarantee that self._empty() will 
return false just because .wait() returns without timing out --
 .wait() returning just means that it may not be a waste of 
time to check for the desired condition.  "notifying" a condvar 
emphatically does not mean that the desired condition holds, 
and any number of other threads can run for any amount of 
time between the times a condvar is notified and some wait()
er wakes up (so even if the desired condition does hold at the 
time notify() is called, it may not anymore by the time a wait()
er wakes).

The check should always be done when .wait() doesn't time 
out, and even if .wait() does time out, self._empty() may 
return false anyway.

Note too that .wait()'s caller holds the associated mutex 
regardless of whether return is due to timeout or notify, and 
the caller needs to release it again in either case.  Creating a 
distinction based on return value creates a new opportunity to 
screw up that part too.

I don't understand this:

> An example is using a condition variable as a sentinel
> for exiting a loop or a polling thread. Using the
> return value one can decide whether to exit the loop or
> not.)

To the extent that I might understand it, it sounds like a 
condvar is gross overkill, and that you'd want something 
simpler (perhaps an Event) in those cases.  But I can't flesh 
out the code you have in mind there.

----------------------------------------------------------------------

Comment By: Michiel de Hoon (mdehoon)
Date: 2005-04-29 06:59

Message:
Logged In: YES 
user_id=488897

This looks like a good idea to me. It will help to clean up
the "get" method in Queue.py, which now has:

                while self._empty():
                    remaining = endtime - _time()
                    if remaining <= 0.0:
                        raise Empty
                    self.not_empty.wait(remaining)

Here, self.not_empty is an object of the class
threading.Condition. It seems odd that first we wait for
self.not_empty.wait to return, and then have to check
self._empty(), even though self.not_empty.wait could have
told us directly if it was notified or it timed out.

I'll write a message to python-dev in support of this patch
(I'm a mere patch reviewer, not an official Python developer).

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=305470&aid=1175933&group_id=5470


More information about the Patches mailing list