【问题标题】:How to use boost context correctly如何正确使用 boost 上下文
【发布时间】:2017-08-08 13:15:58
【问题描述】:

我想使用纤维为我的游戏引擎实现一个作业系统。在网上搜索了一个好的 c++ 实现的 fiber 后,我发现 Boost.Context 是一个很好的起点。

更新1:我想实现自己的调度算法,因此Boost.FiberBoost.CoroutineBoost.Coroutine2不适合我的实现。

在为 x64 架构编译 boost 并尝试从 boost documentation 运行基本示例后,我得到了以下异常:

boost::context::detail::forced_unwind 在内存位置

这是我尝试运行的代码(Visual Studio 2015 企业版,Windows 7):

#include <iostream>
#include <boost\context\continuation.hpp>
namespace ctx=boost::context;
int main()
{
    ctx::continuation source=ctx::callcc
    (
        [](ctx::continuation && sink)
        {
            int a=0;
            int b=1;
            for(;;)
            {
                sink=sink.resume(a);
                auto next=a+b;
                a=b;
                b=next;
            }
            return std::move(sink);
        }
    );
    for (int j=0;j<10;++j) {
        std::cout << source.get_data<int>() << " ";
        source=source.resume();
    }
    return 0;
}

代码运行正确(正确输出:0 1 1 2 3 5 8 13 21 34 55),但是当它完成运行时出现异常。

更新 2:该异常仅发生在发布版本

我想问两个关于提升上下文的问题:

1) 是什么导致了堆栈展开异常,以及如何避免它?

2) 我发现 boost 文档有点肤浅,并且找不到任何其他关于如何使用提升上下文的教程。你能指导我吗 到一些关于提升上下文的好资源/教程?

【问题讨论】:

  • 不要在你的情况下使用std::move返回
  • 有什么替代方案?对于 boost 文档中的所有示例(即使是那些不使用 std::move 的示例),我都遇到了相同的异常。
  • 我没有回答你的问题,因为我不知道答案。我只是提醒你不要在这种情况下使用std::move,它不会有帮助,而且可能只会减慢执行时间。
  • 您是否建议通过引用传递它(接收器)?换句话说,返回 &sink 而不是 std::move(sink)?

标签: c++ boost fibers


【解决方案1】:

首先,强制展开异常 is documented(并且是提供上下文 RAII 支持的原因)。

其次,如果您希望使用基于 Boost Context 构建的 Fibers,请使用现有的库:

更新:

在 Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x64 上使用 Boost 1.64.0 进行测试我无法重现该行为:

【讨论】:

  • 第一。我想实现自己的调度算法,所以 boost fiber\coroutine 不适合我的工作系统。第二。我知道它已记录在案,但我的问题是如何避免它。
  • 更新了我的问题。
  • 确实,在此示例中,未处理的展开异常发生在到达 std::cout &lt;&lt; "Done\n"; 之前:paste.ubuntu.com/25275525。这是个好消息,因为它应该使维护者(Kowalke?)易于追踪问题。仍然可能是编译器问题(例如,如果编译器在某处消除了非平凡的析构函数)。祝你好运!
  • @DontCareBear:您可以使用另一个运行队列实现,查看示例/work_sharing.cpp 或 include/boost/fiber/algo/work_stealing.hpp (spmc-queue)。
  • @DontCareBear:您可以将 std:.atomics 与 boost 一起使用(grep 表示 bosot.fiber 资源中的 atomic)。
【解决方案2】:

返回0后,源对象不在被销毁的位置。

类似:

namespace ctx = boost::context;
int a;
bool stop = false;
{
    ctx::continuation source = ctx::callcc(
        [&stop, &a](ctx::continuation && sink) {
        a = 0;
        int b = 1;
        for (;;) {
            sink = sink.resume();
            if (stop)
                break;
            int next = a + b;
            a = b;
            b = next;
        }
        return std::move(sink);
    });
    for (int j = 0; j < 10; ++j) {
        std::cout << a << " ";
        source = source.resume();
    }
    stop = true;
    source.resume();
}

【讨论】:

  • 您能否澄清一下“源对象不在被销毁的位置”的说法?我不明白这是什么意思。
  • 在 sink = sink.resume() 之后,堆栈可能包含活动对象,必须正确销毁。
【解决方案3】:

如果您在 Windows 上运行并且该错误仅在发布模式下发生,您可能需要检查您的编译器标志是否设置正确。

来自here

使用 fcontext_t 的 Windows:关闭全局程序优化 (/GL) 并将 /EHsc(编译器假定声明为 extern "C" 的函数从不抛出 C++ 异常)更改为 /EHs(告诉编译器假定声明为 extern 的函数" C" 可能会抛出异常)。

【讨论】:

    猜你喜欢
    • 2011-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多