[c++-pthreads] Restating the Jason model
Alexander Terekhov
boo at terekhov.de
Fri Jan 16 16:02:57 UTC 2004
Wil Evers wrote:
[...]
> The situation is actually a bit more complicated: many container
> implementations, including the ones in the C++ standard library, assume
> that the destructors of their elements do not throw. Most likely, an
> exception escaping from one element's destructor will cause the
> remaining elements to be abandoned (and not destroyed at all).
Here's sort of solution:
template<class _FwdIt, class _Tval> inline
void _Uninit_fill(_FwdIt _First, _FwdIt _Last, const _Tval& _Val,
_Nonscalar_ptr_iterator_tag)
{ // copy _Val throughout raw [_First, _Last), arbitrary type
_FwdIt _Next = _First;
try {
for (; _First != _Last; ++_First)
_Construct(&*_First, _Val);
}
/* THIS DOESN'T CATCH *UNEXPECTED* EXCEPTIONS */
/* THIS DOES RETHROW EXCEPTIONS AUTOMATICALLY */
/* NOTHING ELSE CAN BE THROWN FROM THIS SCOPE */
action_on_propagation_of(...) {
for (; _Next != _First; ++_Next)
_Destroy(&*_Next);
}
}
The idea is that if a destructor here attempts to exit with an
exception then std::unexpected() will be invoked at throw point. In a
way, using hypothetical "no_throw {}" (in addition to hypothetical
"action_on_propagation_of()") it is equivalent to
template<class _FwdIt, class _Tval> inline
void _Uninit_fill(_FwdIt _First, _FwdIt _Last, const _Tval& _Val,
_Nonscalar_ptr_iterator_tag)
{ // copy _Val throughout raw [_First, _Last), arbitrary type
_FwdIt _Next = _First;
try {
for (; _First != _Last; ++_First)
_Construct(&*_First, _Val);
}
/* THIS DOESN'T CATCH *UNEXPECTED* EXCEPTIONS */
/* THIS DOES RETHROW EXCEPTIONS AUTOMATICALLY */
/* NOTHING ELSE CAN BE THROWN FROM THIS SCOPE */
action_on_propagation_of(...) {
no_throw {
for (; _Next != _First; ++_Next)
_Destroy(&*_Next);
}
}
}
presuming 2-phase (and a bit "extended") EH, of course.
>
> > This is a somewhat persuasive case for disabling cancel during all
> > destructors, but I'm not sure it outweighs the overhead involved. In the
> > model I proposed, only the EH runtime needs to know about cancellation.
>
> As I tried to say before, my main objection to your model is that,
> depending on the thread's dynamic context, destructors will behave
> differently when hitting a cancellation point. Sometimes, your model
> will protect us from cancellation exceptions, but at other times it
> won't, and I fear the confusion that might result from this.
Not that I really like Jason's model, but "confusion" does already
exist in POSIX; I mean pthread_cleanup_pop(!0) "destructors".
>
> I agree that the overhead of disabling cancellation in all destructors
> could become a problem.
That's good.
> IMO, if we have sticky cancellation, the EH
> runtime doesn't need to be disable cancellation either.
But it has really nothing to do with stickiness.
[...]
> The thing that changes because of cancellation is that some functions
> that didn't throw before will now be licensed to do so. It seems to me
> that most of the participants on this mailing list accept that this will
> require changes to existing code. That could include adding a try/catch
> block to destructor code.
If C++ would impose implicit ("by default") throw() specs on all
destructors AND adopt 2-phase EH with "intelligent" cancel delivery,
things like
object::~object() {
fclose(/*...*/);
}
won't need any changes... and it won't impose any runtime overhead
(on any modern PC-mapped EH impl) as long as you "run across"
cancellation points disabled via throw specs WITHOUT pending cancel
request.
regards,
alexander.
More information about the c++-pthreads
mailing list