4

我一直在写一个延续 - 具体来说,协程 - 库。它类似于 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)

4

1 回答 1

1

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

您必须使用特定于操作系统的 C 调用(如果有的话,我不这么认为),但很可能您只能靠自己使用 ASM。您可以查看 boost.context 库以获取示例解决方案。

于 2012-02-15T04:11:24.520 回答