Boost logo

Boost :

From: Preston A. Elder (prez_at_[hidden])
Date: 2007-11-06 08:33:24


On Tue, 06 Nov 2007 12:40:40 +0000, Phil Endecott wrote:

> Anthony Williams wrote:
>
>> 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
>
> Am I the only one who thinks that not having cancellation points at
> blocking I/O makes this fairly useless? Perhaps I am! I'm curious to
> hear about use-cases where Anthony or Preston's proposals are
> appropriate.

I have a use case in my own app for an interruptable lock and condition.
Though being able to interrupt a sleep would also be cool.

The use case is, I have multiple messages going through my system, they
have a pre-determined path. I want to be able to interrupt them if they
are blocked, and do things like re-route them, hold them, drop them, or
invoke a specific function call on them in the thread that currently owns
the message.

To do this each message is given a UUID, and (using my own version's
idioms) an interruptable_pred. As the message goes through its path,
along the way it goes through both conditions and mutexes where it must
be interrupted. To facilitate this, all mutexes it will wait on in its
path are interruptable_mutexes. The interruptable_pred is updated along
the way (set when we are going to lock, unset when we have got the lock).

This way, I can do something like this:
boost::shared_ptr<message> m = message::find(uuid);
m->interrupt_drop();

And the mutex it is waiting on will be interrupted (an exception thrown)
and the message will be dropped. Actually, to make things work cleaner,
I have actually implemented into my interruptable_pred a boost::function
callback. So that if the callback is defined, it will be called,
otherwise an exception will be thrown (the idea being that function can
throw the exception if it REALLY wants to interrupt).

So in my above implementation - on interrupt, it will interrupt the mutex
(see my previous email on how that works), call a function, which will
change some internal state of the message object and then throw an
exception.

Thereby enabling me to control my message as it goes through the system,
even if it is in condition waits or mutex locks. Even if I have no
control over the duration a lock is held (as long as they use an
interruptable mutex).

> One application for cancellation is to cleanly kill off threads or
> groups of threads when something goes wrong. For example, I may observe
> no activity and assume that a deadlock has occurred. This would require
> that lock-acquisition be a cancellation point.

Yes, this is another purpose I had for this, was breaking a deadlock.
I've long wanted a way to do this without pthread_cancel, which is very
dirty. And an interruptable mutex would be ideal for this.

> I think that, even if this problem could be avoided, delivering a signal
> to the right thread is very hard.
There used to be a pthread_kill() function equivalent to the regular kill
() function in posix. I don't see it anymore. Maybe I immagined it ;)

> Can I suggest that we don't entirely forget about 3) use pthread_cancel
>
> It has some disadvantages, but it's the only solution that offers
> cancellation at blocking I/O.

Yah, but pthread_cancel is more or less a kill -9 of the thread. All
resources are left dangling in the wind, no destructors are called, and
more or less you are in a Bad Situation (tm). Interrupting a lock is a
much preferred method.

PreZ :)


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