我一直在写一个延续 - 具体来说,协程 - 库。它类似于 std::thread (除了它是协作的) - 每个执行上下文都在延续对象中表示。
问题是关于延续对象的破坏。如果在执行上下文没有正常退出的情况下调用了延续对象的 dtor,它应该被销毁对象的上下文强制关闭。
这样,堆栈帧中的每个 C++ 对象都不会被正确销毁。这对任何人来说都可能不是一个愉快的情况——所以我决定找到一个解决方案。
第一次,我想使用异常来展开堆栈帧,如下所示。(请注意,下面只是有缺陷的伪代码。)
coroutine::~coroutine()
{
status = FORCED_EXIT;
switch_to(*this);
}
void coroutine::yield(coroutine& other_coroutine)
{
// switch to other context, halt until invocation by other context
switch_to(other_coroutine);
if (status_ != FORCED_EXIT) {
return; // resume
} else {
throw ContextClosingException;
}
}
void coroutine::entrypoint()
{
try {
entry_function_();
} catch(ContextClosingException& e) {
switch_to(caller_coroutine);
}
}
但是,我发现了一些严重的缺陷。任何如下“吞下异常”的用户代码都将完全打破协作调度的假设。
try {
...
} catch(...) { // ContextClosingException
// do nothing, just swallow exception.
}
所以我需要找到其他方法来调用堆栈展开(或任何其他方式来破坏堆栈对象的延续)。标准一致性方式会很好 - 但延续实现本身依赖于平台特定的 API,因此不可移植的方式是可以接受的。(我用的是win32)