Boost logo

Boost :

From: Anthony Williams (anthony_w.geo_at_[hidden])
Date: 2007-11-06 05:21:26


"Preston A. Elder" <prez_at_[hidden]> writes:

> I just finally checked out the subversion version of boost (I was still
> on CVS, oops!). I noticed that the threading library now supports
> something called 'interruption', which seems to be at the thread level.
>
> While I applaud this effort (see a previous post where I created an
> interruptable_mutex) it has some major deficiencies.
>
> First, its presence in the boost::thread class gives the impression the
> thread can be interrupted at any time. This would mean behavior
> something akin to a pthread_kill() call in POSIX - which it does not.
>
> Second, the only thing it can interrupt in its current implementation is
> a condition

The interface is the same as the "cancellation" interface in N2320
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2320.html), except
renamed to "interruption".

The interruption points are:

thread::join, thread::timed_join
this_thread::sleep
condition_variable::wait, condition_variable::timed_wait
condition_variable_any::wait, condition_variable_any::timed_wait
this_thread::interruption_point

This mirrors the required cancellation points on POSIX platforms.

> - but unfortunately it does this by doing a broadcast to that
> condition which means two things.

Firstly, the broadcast only happens on POSIX platforms --- on Windows, the
thread is notified directly.

> 1) ALL threads waiting on that condition wake up - which is not desired.
> 2) All threads waiting on that condition try to acquire the same mutex,
> meaning the thread you interrupted may have to wait for n other threads
> to acquire the mutex, check to see if they should have woken up, possibly
> do something, and then go back into the condition before the interrupted
> thread finally gets the lock, and the exception is thrown. And all this
> is assuming the coder wrote his code correctly to check to see if he got
> a condition notification correctly (ie. doesn't assume he can do
> something if he gets notified, and tries to do something erroneously).

Condition variables are allowed spurious wake-ups, so the user of the
condition variable has to allow for this possibility. Yes, it is less than
ideal that all the other threads are woken too, for the reasons you
outline. At the moment I'm not sure of a better scheme.

> Third, interruption should also apply to locks - which would in part
> solve the above situation. The problem with this of course is that it is
> less efficient to use a mutex/condition crafted to work with
> interruptions at the lock level.

Yes, and that's why it doesn't happen. All the interruption points are where
the thread is waiting for some event (e.g. a condition to be notified, a
thread to finish, or a time to elapse). Locks should only be held for a short
period, so blocking for a lock should not be a long wait. I don't agree that
it should be an interruption point.

> If you want to continue to offer interruption (which, by the way, I fully
> support!) - I believe it should be done one of two ways.
>
> 1) Use a signal on POSIX systems and find some equivalent mechanism on
> other systems. This will then actually mean what the user thinks -
> thread::interrupt() interrupts the thread, not just breaks out of a
> condition if it happens to be in one.

If a thread is waiting on a condition variable, a signal is not guaranteed to
abort the wait:

"If a signal is delivered to a thread waiting for a condition variable, upon
return from the signal handler the thread resumes waiting for the condition
variable as if it was not interrupted, or it shall return zero due to spurious
wakeup."

The only way I know to ensure that the thread being interrupted wakes from the
condition variable is to broadcast the condition variable. The alternative is
that boost::condition_variable does not actually use a pthread_cond_t in the
implementation, and I'm not keen on that idea at all.

> 2) Move interruption to its own series of structures. Like I did, with
> an interruptable_mutex. The advantage of this is twofold:
> 1) It can be implemented in a non-platform specific manner, using
> existing data structures, so you implement the interruptable version once
> (utilizing boost::mutex and boost::condition) and you don't have to care
> about the underlying platform. This means it doesn't require any OS
> specific support.
> 2) It works exactly as the user thinks. An interruptable_mutex can be
> interrupted while blocked on something to do with it (meaning when trying
> to acquire a lock on it, OR when waiting on a condition with it).

I'm not keen on this approach, as it really does mean that the thread can only
be interrupted at the defined points.

> Once again, I applaud you for including interruptions into
> boost::threads, but it really should be complete. I am probably going to
> try and re-write my interruptable_mutex to work with the new threading
> architecture (I will have to understand it better, and figure out how to
> replicate the current functionality), but in the mean time, something for
> you all to think about.

Thank you for your input.

Anthony

-- 
Anthony Williams
Just Software Solutions Ltd - http://www.justsoftwaresolutions.co.uk
Registered in England, Company Number 5478976.
Registered Office: 15 Carrallack Mews, St Just, Cornwall, TR19 7UL

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