Boost logo

Boost :

From: David Abrahams (dave_at_[hidden])
Date: 2002-10-16 21:58:39


Jonathan Biggar <jon_at_[hidden]> writes:

> David Abrahams wrote:
> > > I've never seen a workable use case for calling wait() on a
> > > condition without performing some test on the data that the
> > > condition is protectiong, and that means the lock has to be acquired
> > > first. That's the basic design pattern for using locks & condition
> > > variables:
> > >
> > > lock->acquire();
> > > while (!predicate())
> > > cond.wait();
> > > // modify protected data here
> > > lock->release();
> >
> > Right. But I'm suggesting that everything up to the comment can be
> > encapsultated in the version of wait that takes the predicate.
>
> It's not very symmetrical to have the lock acquisition inside the wait()
> call, but the release() outside, though, and makes using a lock guard
> problematical.

Not at all:

     template <class ScopedLock, class Predicate>
     wait(ScopedLock& lock, Predicate pred)
     {
         if (!lock.locked())
             lock.lock(); // instead of throw
         while (!pred())
             wait(lock);
     }

I'll grant you it's not very symmetrical, but it eliminates the IMO
silly "you didn't have the lock, so you can't wait for notification"
exception.

> Although you could have a version of wait that takes another template
> "action" functor, and call it like this:
>
> cond.wait(predicate, action);
>
> and encapsulate the loop entirely.

I don't see what you're getting at here. The loop is already entirely
encapsulated in the current version. What's action supposed to do?

> > Maybe I'm still missing something, but I don't see it yet. The
> > version of wait that takes a predicate already contains code for
> > testing the predicate and in a loop. I don't see a reason to make
> > the user test it and branch around the wait. But then, maybe I'm
> > describing a slightly higher-level construct that just shouldn't
> > be called a condition wait.
>
> Perhaps like I suggested above?

I don't know, since I don't understand your suggestion.

> > > > > > f. The non-predicate form of timed_wait Effects: clause
> > > > > > ends with "...and then reacquires the lock". This
> > > > > > appears to mean the lock is reacquired regardless of
> > > > > > whether timeout arrives before notification. I think
> > > > > > that can't be intentional. Can it?
> > > > >
> > > > > Yes, that is intentional. The required condition variable
> > > > > pre- and post-condition logic for wait() is that the
> > > > > associated lock is locked. Without that, you get race
> > > > > conditions.
> > > >
> > > > Only if you access the associated data, right? Well, it wasn't
> > > > completely clear to me that that was supposed to be allowed in
> > > > the case of timeout. It means that even with a timeout, you
> > > > can't come back from wait() if some other thread has the mutex
> > > > locked. I think it would be good to spell that out somewhere
> > > > in the condition docs.
> > >
> > > Right, but you have to access the associated data to see if you
> > > are going to call cond.timed_wait() in the first place.
> >
> > No, I mean /after/ the return from timed_wait. At that point, if
> > you aren't going to touch the data, you don't need to have the
> > mutex. If you're going to touch it regardless of whether notify()
> > occurred. You need it.
>
> I've seen use cases where you have to do some "clean up" after the
> timeout that still needs to have the lock held. If timed_wait()
> released the lock, you wouldn't be able to do that.

Fine. I'm just asking that the docs devote a sentence to this, to make
it clear it's part of the design.

-- 
                    David Abrahams
dave_at_[hidden] * http://www.boost-consulting.com
Building C/C++ Extensions for Python: Dec 9-11, Austin, TX
http://www.enthought.com/training/building_extensions.html

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk