|
Boost : |
From: Preston A. Elder (prez_at_[hidden])
Date: 2007-11-05 22:53:31
Hey all,
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 - but unfortunately it does this by doing a broadcast to that
condition which means two things.
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).
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.
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.
Or
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).
Once again, I'll post the code to my interruptable_mutex - though of
course it is based on the CVS (aka. boost 1.34.1) threading library:
http://www.neuromancy.net/fisheye/browse/mantra/trunk/Mantra-I/mantra/utils/interruptable_mutex.h?r=419
It uses an interruptable_pred as the predicate that signals the interrupt
should happen. So you create an interruptable_pred that has a reference
to an interruptable_mutex, and then lock the predicate or pass the
predicate to a condition (I had to specialize the wait() functions in
condition to make this work, but it DOES work). This allows you to have
a single lock, but then have each thread have its own predicate, or even
multiple threads to use the same predicate (so a single interrupt
interrupts multiple threads potentially).
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.
PreZ :)
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk