[cpp-threads] Issue 1369 --- thread safety of std::rethrow_exception

N.M. Maclaren nmm1 at cam.ac.uk
Sat Nov 13 11:56:02 GMT 2010


On Nov 13 2010, Boehm, Hans wrote:
>
> 
> I'm a bit concerned that we're talking about a bunch of different things
> here.  I think the most worrisome scenario for this issue is a program
> that invokes a function with async() and then turns the result into a
> shared_future, and makes the result f available to multiple threads.  If
> the asynchronously run function throws an exception, then that exception
> e may be thrown in several different threads calling f.get().  If one of
> those threads modifies e, we have a data race.

You get more than one form of data race, actually.  In addition to the
form that you have been dealing with, you can also get the logical data
race caused by the conflicting use of a non-shareable resource.  GPUs
and other attached processors are a good example of that.

> (The issue of whether you want to pass exceptions between threads is 
> different. C++ certainly doesn't prevent you from handling exceptions 
> locally, but I agree with Anthony that that's not always the right 
> thing.)

Do you REALLY want to open the wormcan of one thread asychronously
changing the behaviour of another?  POSIX originally specified that,
until certain vendors gibbered (I had a bit player part in that), so the
insanity is at least optional.

Note that I am not saying that the initial handler should not reraise
ANOTHER exception created from the first one on another thread.

Taking a look at 18.8.5 Exception Propagation [propagation] indicates
that a thread A cannot handle an exception raised in thread B unless
SOME handler for thread B was called to create an exception_ptr object,
that is precisely what C++ specifies.

I haven't looked into this area, as I thought it was forbidden, but
a quick glance shows significant problems with the existing wording.

    5.2 Constructors and destructors [except.ctor]
    As control passes from a throw-expression to a handler, destructors
    are invoked for all automatic objects constructed since the try
    block was entered. The automatic objects are destroyed in the
    reverse order of the completion of their construction.

Now, that's not a problem under two circumstances:

    1) Destructors are purely scope-based (like try-catch), but C++
isn't like that.

    2) Destructors are always 'passive' and never invoke anything
with cross-thread implications.  I haven't seen any such constraint.

Without any constraints, you get delights like an exception raised
by a thread A being handled in thread B after thread A has been killed,
by which time thread C has got control of the resource that needs
cleaning up.  With some thought, I could probably think of nastier
gotchas.

It's an EVIL problem.  Been there - done that :-(

Regards,
Nick Maclaren.





More information about the cpp-threads mailing list