Boost logo

Boost :

From: Preston A. Elder (prez_at_[hidden])
Date: 2007-10-25 13:46:50


On Thu, 25 Oct 2007 17:53:05 +0100, Anthony Williams wrote:

> "Preston A. Elder" <prez_at_[hidden]> writes:
>
>> I have written a refinement on boost::mutex that allows for it to be
>> interrupted while waiting to acquire the mutex by altering a predicate
>> (once the mutex is acquired, it acts like a regular mutex).
>>
>> Here is the code:
>> http://www.neuromancy.net/fisheye/browse/mantra/trunk/Mantra-I/mantra/
utils/interruptable_mutex.h?r=419
>
> It's an interesting idea. I'm yet to be convinced that it's worth adding
> to boost.thread, though --- I'd rather just use a condition variable.
>
> Anthony

Well, in one respect, the interface I provide is just a nice way of not
forcing the end-user to write a condition themselves. But its more than
that.

If you recall the situation I said earlier, where you do:

interruptable_pred pred(mtx);
cond.wait(pred);

Assuming you do a similar thing in multiple threads, so you have multiple
threads each with their own predicate object (which in turn is
referencing the same mutex), and they wait on the same condition. Then I
do this:

cond.notify_all();

All threads will break out of the condition wait, and be waiting on the
same mutex, one will acquire the mutex the others block. The above code
using my interruptable_mutex/pred makes this no problem, I can still
modify my predicate and break out. Using a hand-crafted mutex and
condition to simulate an interruptable_mutex/pred presents two problems:

1) I can't pass a condition to another condition, so there is no way to
have some kind of separate interruption (which is what a pred is). So
there is no way to just signal the condition to stop waiting for the re-
acquire of the lock after using that lock in another condition.
2) Because of this, you pass the mutex to the condition. When the
condition exits wait state, it is trying to acquire the lock, and blocked
on a mutex::do_lock(). There is no way to interrupt this.

Plus, the big problem with just using a condition is this:

boost::mutex::scoped_lock sl(mtx);
if (cond.wait(sl)) { ... }

You have already blocked trying to acquire the mutex, before you ever hit
the condition wait. Plus, even DO the condition wait if you have already
got the lock, unless you are proposing:

// somewhere else, these are the lock and condition protecting a queue<>
// or whatever.
boost::try_mutex mtx;
boost::condition cond;

// In my code where I must wait on the condition, say pushing onto a
// queue<>.

boost::mutex mylock;
bool breakout;

boost::try_mutex::scoped_try_lock sl(mtx);
while (!sl.locked())
{
    boost::mutex::scoped_lock tmplock(mylock);
    cond.wait(mylock);
    if (breakout)
        throw std::runtime_exception("Broken out!");
    tmplock.unlock();
    sl.try_lock();
}

and then elsewhere I decide I want to interrupt the thread blocked
waiting for the queue<>'s lock, so from another thread I do:

boost::mutex::scoped_lock sl(mylock);
breakout = true;
cond.notify_all();
sl.unlock();

This will achieve the interruptable mutex semantics I wrote I guess, but
still will not work inside a condition, and is a lot of ugly code to use
every time you want to be able to interrupt your lock.

Preston


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