Sign in to follow this  
Prune

Forcing exception in another thread

Recommended Posts

The MSVC example of using exception_ptr/rethrow_exception()/current_exception() shows only how to send exception data to another thread, but the user has to explicitly call rethrow_exception(), and so the exception is not rethrown automatically. I need a method to overcome this, so that as soon as I save an exception in a thread, the exception would be immediately rethrown in the handler thread. I assume this would involve using signals and signal handlers, but I'm not well familiar with these on neither Windows nor Linux. I'd like to try in Windows first. Any pointers as to the best way to do this? From what I've read about signal handlers, I'm not sure how to cause the exception to have the effect as if it were raised in a particular scope of the thread that does the handling...maybe longjmp?

Share this post


Link to post
Share on other sites
Anyone?

[Edit] I have found this solution for Windows: http://www.codeproject.com/KB/exception/ExcInject.aspx but I don't know how to accomplish this under Linux as well...

[Edited by - Prune on December 10, 2010 2:40:50 PM]

Share this post


Link to post
Share on other sites
I am not sure if this is possible at all in any other way but to write your own mini-debugger (using the debug API, you will get an event for every unhandled exception). Other than this, exceptions normally stay in the same thread, unless you do something explicit and special.

Why would you want to do this, anyway? It usually does not make much sense to catch exceptions in a different thread, unless the handler simply terminates the process. The actual purpose of exceptions is to handle some unexpected failure in a graceful way, i.e. backing off as much as needed so the program can still continue if possible at all.
I don't see how a handler thread knows enough about what is going on in some random other thread to be able of doing this.

Share this post


Link to post
Share on other sites
Quote:
Original post by samoth
I am not sure if this is possible at all in any other way but to write your own mini-debugger (using the debug API, you will get an event for every unhandled exception). Other than this, exceptions normally stay in the same thread, unless you do something explicit and special.

Well, given the above link, it's possible in Windows at least. That would make me guess it should somehow be possible in Linux as well.

Quote:
Why would you want to do this, anyway? It usually does not make much sense to catch exceptions in a different thread, unless the handler simply terminates the process. The actual purpose of exceptions is to handle some unexpected failure in a graceful way, i.e. backing off as much as needed so the program can still continue if possible at all.
I don't see how a handler thread knows enough about what is going on in some random other thread to be able of doing this.

The exception is thrown in the current thread so "backing off" is already accomplished. But the other thread in my case is able to do further recovery, by loading some DLLs and doing a bunch of other stuff including restarting certain threads. It's hard to explain because the structure of the system I'm working on is nontrivial.

Share this post


Link to post
Share on other sites
Quote:
Original post by Prune
The MSVC example of using exception_ptr/rethrow_exception()/current_exception() shows only how to send exception data to another thread, but the user has to explicitly call rethrow_exception(), and so the exception is not rethrown automatically. I need a method to overcome this, so that as soon as I save an exception in a thread, the exception would be immediately rethrown in the handler thread.


Bad idea. What if the other thread is doing this:


mutex.Lock();
do_something();
mutex.Unlock()


(Of course, the user probably should have used RAII for the lock, but in this case they got lazy for whatever reason).

If your exception is "forced" in to this thread before the call to mutex.Unlock() but after mutex.Lock(), your program is now completely screwed.

I chose a mutex because it's a particularly devastating example, but there are countless other kinds of resource that could be leaked in a similar way with various terrible consequences.

The boost threads library has an interruption-points feature which allows you to do this kind of thing, but the exception is only checked at certain "safe" points. This is probably the closest thing to what you want (though I'd suggest a redesign to avoid the issue altogether might be a better course of action).

Share this post


Link to post
Share on other sites
Exceptions are stack unwinding mechanism. Stack is unwound either until it reaches the top, or until exception is handled.

Each thread has its own stack.

This makes threads and exceptions mutually exclusive. At least conceptually.


In practice it is sometimes beneficial to signal exceptions across threads. Perhaps to a logger or some coordinating mechanism. But at that point the original exception no longer serves its purpose. It is merely a log or a message, not an exception - the handling thread did not have an exception and cannot unwind a stack.

And if exception records a stack trace, the handling thread has no use for it - that stack no longer exists.


There are usually two separate issues here:
- Detecting abnormal condition in one of worker threads, possibly fatal, with the need to restart them.
- Having a centralized logging or notification system.

The solution to these is same. The exception must first be serialized in some way, maybe just a .what() will be enough. This message is then passed to handler thread using usual inter-thread communication. Handler thread does not deal with exceptions but simple user-defined objects.

Share this post


Link to post
Share on other sites
the_edd, your example applies just as much to the case where the exception is thrown in the same thread by do_something() :D

In fact, I use RAII for pretty much everything.

Checkpoints is a good idea, but I really need both, because a few things need to be handled immediately.

Antheus, the handler thread needs happens to be my main thread which does various other things and needs to be interrupted; it would be very difficult to refactor so I have a separate handler thread that simply does WaitForMultipleObjects() (or select()) waiting for error events. Things would work out much better if I can have an exception generated because then RAII would take care of a lot of things, including some of the recovery mechanisms. This way, the same exception both unwinds the stack and calls destructor/cleanup in the originating thread, and takes care of the serialization issue you mentioned in the main thread.

Share this post


Link to post
Share on other sites
Quote:
Original post by Prune
the_edd, your example applies just as much to the case where the exception is thrown in the same thread by do_something() :D


Not quite. If I know that do_something() does not throw an exception, that code should be perfectly safe.

If some other thread injects an exception without my say-so, it's not safe.

In fact even if RAII was used in my example (some kind of scoped-locking mechanism), there's still no guarantee of correctness. If the exception is injected just after the constructor of the scoped lock calls mutex.Lock() but before the constructor returns, same problem (because unwinding triggered in a constructor does not call the destructor).

EDIT: and you could take it a step further; what if the exception is injected somewhere in the middle of the call to mutex.Lock()?

Share this post


Link to post
Share on other sites
Quote:
Original post by Prune

the handler thread needs happens to be my main thread which does various other things and needs to be interrupted;
Thread interruption has been effectively abandoned. It's simply too problematic, even if well designed.

The boost's interruption is effectively just that - periodic checking for external events.

Quote:
Things would work out much better if I can have an exception generated because then RAII would take care of a lot of things, including some of the recovery mechanisms.
But this doesn't make sense. If thread A throws an exception, B is completely independent. There is nothing to unwind in B since exception didn't happen there.

B may choose to throw a new exception to clean up its own stack upon learning that A has shutdown. In code, this looks something like this:
void thread_func() {
try {
// do the real work
} catch (std::exception & e) {
// unhandled exception
worker_exceptions.push.back(this.id(), e, ...);
}
// exit this thread normally
}

void main() {
while (running) {
// do something
if (!worker_exceptions.empty()) {
throw some_exception(foo, bar, baz);
}
// keep running
}
}


No matter how it's implemented, this introduces asynchronous messaging. It also needs to handle all the associated cases, such as main not responding.

If worker thread attempted to interrupt main thread immediately - what would happen if during that time another thread interrupted main thread while it's cleaning up and exiting.

Quote:
need to be handled immediately
Threads cannot do that. Unless running on a hard real-time OS, there is no guarantee main thread will ever wake up - it can remain suspended/unscheduled for arbitrary amount of time.

Quote:
signal handlers
This is how interrupts work. But due to many issues they are also notoriously difficult to program, especially in user space. Making a tiny mistake inside a handler can bring down the system. Today's userspaces are highly isolated for this very reason.

The method presented above avoids the design issues present in interrupts while retaining the desired functionality. Anything beyond, such as any attempts to directly interact with code flow is simply not adequately supported by C or C++, especially in the automagic parts (destructors, RAII), which means results are unpredictable.

Share this post


Link to post
Share on other sites
That code over at CodeProject is scary, if you ask me. First it uses SuspendThread, which is nasty stuff that should really never be used if you can help it at all (causes deadlocks in combination with wait functions), and then it tampers with the other thread's context. Which, meh... sure, will probably work, but... bleh. It's nasty.

If you do need to signal an exception, you can always just post a thread message. This is not the fastest thing in the world, but seeing how exceptions occur exceptionally, it will be fast enough. No tampering with half-documented internals that might change next week if you're unlucky or might not run on a different system.

But again, for most exceptions, handling them in another thread does not make an awful lot of sense. Logging or killing the process can be done easier and faster, without exceptions.
And pretty much everything else requires "knowledge" (this is what Antheus referred to with stack unwinding) that is not available to the other thread. Plus, the stack unwinding will be done anyway.
And lastly, in the (admittedly rare) cases where an exception handler can actually do something useful (something different than killing the process) only make sense in the same thread. For example, if you catch bad_alloc, you might want to try to free some memory that you can purge and try allocating again. The program could then (in the lucky case) continue as before, and nobody would ever know.
This wouldn't make sense when done in another thread.

Share this post


Link to post
Share on other sites
Arbitrarily throwing simply doesn't make sense - you cannot write exception safe code without relying on no-throw code, and forcing an exception to jump threads means that no code is no-throw.

For example...
Quote:
(Of course, the user probably should have used RAII for the lock, but in this case they got lazy for whatever reason).

What if they'd used RAII and the exception occurs during the destructor?

Share this post


Link to post
Share on other sites
@samoth

From what I understand, it's necessary to suspend a thread before altering it's context, but I agree that posting a message to a handler that in turn throws the exception is a much better approach.

Share this post


Link to post
Share on other sites
While I am strongly considering redesign to avoid doing this, I want to point out that it is trivial to add a flag that is set by the target thread whenever it is in a section which should not be interrupted. The catch block in the sending thread which has saved an exception_ptr would check that flag immediately after suspending the thread and resuming right away if it's set. Another guard is that system calls do not get interrupted, at least on Windows--I don't know about Linux.

Share this post


Link to post
Share on other sites
Quote:
Original post by Prune
While I am strongly considering redesign to avoid doing this, I want to point out that it is trivial to add a flag that is set by the target thread whenever it is in a section which should not be interrupted.


Nope :)

There are threads involved. A statement such as "dont_interrupt = true" does not make its side-effects visible to all threads (the one injecting the exception, for example). In theory the C++ standard doesn't even know about threads. In practice it means using a lock. And now we're back to square one. Perhaps there's a solution, but "trivial" it ain't.

Share this post


Link to post
Share on other sites
Quote:
Original post by Prune
Yes, it would require a lock, but how is it back to square one?


Sorry, "square one" was a poor choice of words. I meant to imply that if you're actually communicating (using proper synchronization primitives) with the thread that your interrupting, you've just re-invented a very hazardous implementation of boost's interruption points.

Share this post


Link to post
Share on other sites
I've come up across a design issue here: where do I best null a stored exception? Execution continues after the catch {}, but it would be pretty ugly code to insert check after every catch block to see whether the exception of a particular type so the associated exception_ptr would be nulled (if it's not nulled, then if the program continues the next checkpoint would end up rethrowing the same exception. One idea I thought would be to wrap any exception with one that nulls its exception_ptr in its destructor, but I'm not sure that's a good idea and it still adds quite a bit of code.

For example in the main thread:

while (SomeObjectsStillRunning())
{
...
{...{ // Some scope
...
if (!(object.someThreadException == 0)) rethrow_exception(object.updateThreadException); // Checkpoint
...
}...}
catch (exception &e)
{
... // Some logging
... // First recovery attempt
... // If no good, submit reloading task for object and some dependencies to loader thread
// --> Here <-- how to null someThreadException regardless which one of various objects it came from?
}
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this