有没有任何方法可以在C++中导致整个堆栈框架展开?(使用异常除外)

Is there any method that causes whole stack frame unwinding in C++? (except using exception)

本文关键字:框架 异常 堆栈 方法 任何 C++ 有没有      更新时间:2023-10-16

我一直在写一个延续-在特定的协同程序库中。它类似于std::thread(只是它是协作的)——每个执行上下文都在continuation对象中表示。

问题是关于连续对象销毁。如果在执行上下文没有正常退出的情况下调用了延续对象的dtor,则应该通过销毁对象的上下文来强制关闭它。

这样,堆栈框架中的每个C++对象都不会被正确地销毁。这可能对任何人来说都不是一个愉快的情况——所以我决定找到一个解决方案。

第一次,我想用异常来展开下面的堆栈框架。(请注意,下面只是有缺陷的psuedo代码。)

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)

在C++标准中,除了异常之外,没有任何东西允许展开堆栈。Coroutines(或对corountines的支持)可以在C++11之后提出(在Going Native会议期间讨论)。

您将不得不使用特定于操作系统的C调用(如果存在,我不这么认为),但很可能您只能使用ASM。您可以查看boost.context库中的示例解决方案。