What are the real issues?

Matt Austern austern at apple.com
Tue Jan 6 19:33:47 UTC 2004


I'm just trying to trace back why people see C++ thread cancellation as 
a problem.

First: the usual assumption has been that thread cancellation is most 
naturally represented in C++ as an exception.  That's because the POSIX 
model for thread cancellation is that if you cancel a particular 
thread, then, the next time the thread reaches one of a set of 
well-defined cancellation points, it'll perform some cleanup and then 
stop.  In C the cleanup is via handlers that you register.  We could 
have that model in C++ as well, but most C++ programmers would think 
it's very strange that you would stop execution at some point without 
cleaning up the stack.  And once you're talking about stack cleanup, 
i.e. invoking destructors, you're talking about something that's close 
enough to an exception that it makes no difference.

The Itanium C++ ABI, which gcc adopted, made cancellation a special 
kind of exception, "forced unwinding", so that a thread can't just 
catch the cancellation exception and swallow it.  The idea was that a 
thread may disable cancellation tempoarily, but that once a 
cancellation has begun it can't be thrown away.  This was a slightly 
controversial decision at the time, and maybe it's at the heart of the 
real issue.

Second: the immediate issue was that some people saw a contradiction 
between this model and the C++ library specification.  For example, 
POSIX says that read() is a cancellation point.  But it's reasonable to 
assume that std::istream:;read() invokes POSIX's read() system call, 
and the C++ standard says that (under ordinary circumstances) 
std::istream doesn't throw.  If the cancellation exception were an 
ordinary exception instead of special forced unwinding, what would 
happen would be that istream would invoke its streambuf, the streambuf 
would call read(), read would throw a cancellation exception, then 
istream would catch the exception, swallow it, and set and error flag.  
Forced unwinding means that the cancellation exception will propagate 
even though istream tries to swallow it.  This means that an exception 
will propagate from istream when the C++ standard says it's not 
supposed to.

Third, some people simply object to having cancellation be an exception 
(or anything that looks like an exception): it means there are some 
functions that can throw exceptions in the presence of threads that 
wouldn't throw in a single-threaded program.

It's actually pretty hard for me to imagine any model for thread 
cancellation that's very different from the POSIX.  Anything that 
doesn't involve thread execution stopping sounds more like a 
communication mechanism than a cancellation mechanism.  Seems to me 
that the only real issues for debate are which functions are 
cancellation points, how a thread can enable and disable cancellation, 
whether a thread should be allowed to disregard a cancellation request 
once it has been received, and what kind of cleanup a thread performs 
before it stops.

My feeling: it's just plain inevitable that a multithreaded program has 
more functions that might throw than a single-thread program.  Dealing 
with this is part of what it means to make a program thread-safe.  We 
might argue that POSIX defines too many cancellation points, and that 
cutting it down to a smaller number (and, especially, getting rid of 
the functions that POSIX says may or may not be cancellation points) 
would make it easier to write correct code.

But as I said, I think the really fundamental issue is whether a thread 
should be allowed to receive a cancellation request, start to do some 
work as a result of the request, and then decide that it doesn't want 
to be cancelled.  If we think that's reasonable then I think what we 
should probably do is abandon the notion of forced unwinding and make 
cancellation into an ordinary exception.  If we do that then the 
std::istream contradiction goes away.  The cost, of course, is that it 
might become surprisingly hard to cancel some threads.

			--Matt




More information about the c++-pthreads mailing list