Scope guard and coroutine destroy, what to do with aborted suspension?

168 views
Skip to first unread message

TONGARI J

unread,
Apr 18, 2018, 12:06:45 PM4/18/18
to ISO C++ Standard - Discussion
N4152 explains why  std::uncaught_exceptions() is needed to implement scope guard.

With coroutine, the problem becomes more interesting, because now we have 3 reasons for stack-unwinding:
  • Normal cleanup
  • Exception
  • Aborted suspension
The last one is achieved by suspending the coroutine and calls destroy on it.

You can see that in case of aborted suspension, the Transaction is considered succeeded, which might not be desired.
Probably we need a way to distinguish it from normal cleanup.

Does anybody have an opinion on this?

ben....@gmail.com

unread,
Apr 18, 2018, 1:29:31 PM4/18/18
to ISO C++ Standard - Discussion
I think it's tricky, because I don't think an aborted suspension is always an error.  Consider a generator over an infinite (or nearly) infinite series.  When the user has generated enough elements from the generator, they will abort it.  That doesn't feel like a failure to me.

Rather than try to classify abort as a success or a failure, I would say just make a scope_abort class and be explicit.  There would still need to be some way to differentiate between aborts and returns, but at least with a new class you can get a straightforward answer on the semantics.

gorni...@gmail.com

unread,
Apr 18, 2018, 2:17:12 PM4/18/18
to ISO C++ Standard - Discussion, ben....@gmail.com
scope_guard (as in https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Scope_Guard) should work fine, since, it is pretty much an equivalent of hand crafted RAII class.
However, things that require uncaught_exceptions() SHOULD NOT work in coroutine in general.

The suggested usage for uncaught_exceptions() is to grab an uncaught_exceptions() in constructor and compared it to the one in destructor.
If there is a suspension in between, comparing uncaught_exceptions() won't give you anything of value.

Peter Sommerlad

unread,
Apr 18, 2018, 4:13:34 PM4/18/18
to std-dis...@isocpp.org
I would have an easier life if someone could explain to me if resumption can happen from exception handling?

sent from a mobile device.
Prof. Peter Sommerlad
--

---
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-discussio...@isocpp.org.
To post to this group, send email to std-dis...@isocpp.org.
Visit this group at https://groups.google.com/a/isocpp.org/group/std-discussion/.

gorni...@gmail.com

unread,
Apr 18, 2018, 5:20:10 PM4/18/18
to ISO C++ Standard - Discussion
That is easy.

f() {
// assume that at this point uncaught_exceptions() == 0
for (auto x: gen())
  if (x != 0)
     throw 1;
}

where gen() is:

generator<int> gen() {
  scope_fail (bla);
  co_yield 1;
}

When generator is created, uncaught_exceptions() is zero so scope_fail will remember it as zero.
When exception is unrolling function f() it will run the destroy the coroutine (which means that it will need to resume it to run destructors for all of the objects that are live at the point of suspension), therefore destructor of scope_fail will observe unhandled_exception count > than the one captured in the constructor.

For this problem to go away, scope_fail / scope_success should be language facilities, not, clever tricks using, formerly non-standard, implementation details of the current crop of compilers.

TONGARI J

unread,
Apr 18, 2018, 9:55:31 PM4/18/18
to ISO C++ Standard - Discussion, ben....@gmail.com, gorni...@gmail.com
On Thursday, April 19, 2018 at 2:17:12 AM UTC+8, gorni...@gmail.com wrote:
scope_guard (as in https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Scope_Guard) should work fine, since, it is pretty much an equivalent of hand crafted RAII class.
However, things that require uncaught_exceptions() SHOULD NOT work in coroutine in general.

The suggested usage for uncaught_exceptions() is to grab an uncaught_exceptions() in constructor and compared it to the one in destructor.
If there is a suspension in between, comparing uncaught_exceptions() won't give you anything of value.

That's how it works currently. My question is that, since we now have a 3rd way for stack-unwinding, we also need some way to distinguish it from others to customize the scope guard behavior.
What do you suggest?

Peter Sommerlad

unread,
Apr 19, 2018, 6:36:30 AM4/19/18
to std-dis...@isocpp.org
I do not think that adding more language facilities are a good way to
solve that problem.

I would just add a note that neither scope_success nor scope_fail work
as one might expect if used in a coroutine.

And I believe that scope_fail in gor's example should actually be
called, because one is exiting the coroutine (implicitly) with an
exception, so destroying locals happens under exceptional stack
unwinding and IMHO that is intended.

gorni...@gmail.com wrote:
> For this problem to go away, scope_fail / scope_success should be
> language facilities, not, clever tricks using, formerly non-standard,
> implementation details of the current crop of compilers.

--
Prof. Peter Sommerlad

Institute for Software: Better Software - Simple, Faster!
HSR Hochschule für Technik Rapperswil
Oberseestr 10, Postfach 1475, CH-8640 Rapperswil

http://ifs.hsr.ch http://cevelop.com http://linticator.com
tel:+41 55 222 49 84 == mobile:+41 79 432 23 32
fax:+41 55 222 46 29 == mailto:peter.s...@hsr.ch

gorni...@gmail.com

unread,
Apr 19, 2018, 3:35:10 PM4/19/18
to ISO C++ Standard - Discussion
You are probably right. Though, my reading of scope_fail / scope_success that the success or failure is related to what is happening in the body where scope_fail/exit lexically present and not from the outside. For me they are extensions of try/catch machinery. If you think of them that way, I would imagine that failure in the caller of the coroutine should not affect what is observed in the body of the coroutine.

In earlier example if I replace `throw 1;` with break `break;` coroutine will still be cancelled/abandoned/destroyed in the middle of the execution, but, it will be perceived by scope_guard as successful completion.
Reply all
Reply to author
Forward
0 new messages