Boost asio:“co_spawn”和“spawn”作为异步启动函数会导致段错误

问题描述 投票:0回答:1

我同时使用了 stackful 协程(如下所示:https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/overview/composition/spawn.html)和 C++20 协程(https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/overview/composition/cpp20_coroutines.html)在我的项目中。这是一个例子:

#include <boost/asio.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/spawn.hpp>
#include <iostream>

using namespace boost::asio;

io_context ioctx;
void stackful_coroutine(yield_context yield);

awaitable<void> cxx_coroutine() {
  std::cout << "In cxx_coroutine" << std::endl;
  co_await spawn(ioctx, stackful_coroutine, use_awaitable);
  co_return;
}

void stackful_coroutine(yield_context yield) {
  std::cout << "In stackful_coroutine" << std::endl;
}

int main() {
  co_spawn(ioctx, cxx_coroutine(), detached);
  ioctx.run();
}

这不会出现任何错误,并且生成仅用作另一个异步操作。

但是,当我切换顺序时:


#include <boost/asio.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/spawn.hpp>
#include <iostream>

using namespace boost::asio;

io_context ioctx;
void stackful_coroutine(yield_context yield);

awaitable<void> cxx_coroutine() {
  std::cout << "In cxx_coroutine" << std::endl;
  co_return;
}

void stackful_coroutine(yield_context yield) {
  std::cout << "In stackful_coroutine" << std::endl;
  co_spawn(ioctx, cxx_coroutine(), yield);
}

int main() {
  spawn(ioctx, stackful_coroutine, detached);
  ioctx.run();
}

我遇到分段错误!

此外,即使我只使用堆栈协程,我也会遇到分段错误,如下所示:

#include <boost/asio.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/spawn.hpp>
#include <iostream>

using namespace boost::asio;

io_context ioctx;

void stackful_coroutine(yield_context yield) {
  std::cout << "In stackful_coroutine" << std::endl;
  spawn(
      ioctx, [](auto yc) { std::cout << "Spawn inside spawn" << std::endl; },
      yield);
}

int main() {
  spawn(ioctx.get_executor(), stackful_coroutine, detached);
  ioctx.run();
}

我不确定这是否是一个错误,或者我是否遗漏了一些东西...... 我正在使用

gcc (Debian 12.2.0-14) 12.2.0
和 Boost 1.83.0。

c++ c++20 boost-asio c++-coroutine boost-coroutine
1个回答
0
投票

我认为您遇到了 Asio 1.24/Boost 1.80.0 中引入的错误。

我注意到提交发生了行为变化5bbdc9b添加了新的spawn()重载,符合异步操作的要求before1并在之前和之后进行了检查。

我无法给出满意的建议。我可以向您展示我所尝试过的内容(基于您最后一个最简单的示例)。

所有替代方案(例如继承内部 coro 的

yield
上下文,该上下文已被弃用但仍然存在)都不起作用。另请注意,旧样式实际上并没有达到相同的结果,因为无论
spawn
上下文是否继承,内部
yield
都不是“等待”的。 ́\(ツ)/́ 我想这使它“不是一个重大改变”,因为该功能在 Asio 1.24 之前并不存在。

注意,我还尝试向内部处理程序添加工作防护,但没有什么区别。

住在Coliru

#define BOOST_ASIO_ENABLE_HANLDER_TRACKING 1
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <iostream>
#if BOOST_ASIO_VERSION >=                                                                                    \
    10'24'00 // Asio 1.24.0,  Boost 1.80.0
             // https://www.boost.org/doc/libs/1_83_0/doc/html/boost_asio/history.html#boost_asio.history.asio_1_24_0___boost_1_80
    #define NEWSTYLE 1
#else
    #define NEWSTYLE 0
#endif

namespace asio = boost::asio;
asio::io_context ioctx;

void coro(asio::yield_context yield) try {
    std::cout << "Start coro" << std::endl;

#if NEWSTYLE
    auto ex = yield.get_executor();
#else
    auto ex = asio::get_associated_executor(yield);
#endif

    asio::spawn(
#if NEWSTYLE
        ioctx, // or: yield, // or: ex
#else
        yield,
#endif
        [](asio::yield_context yc) {
            std::cout << "Spawn inside spawn" << std::endl;
            post(yc); // just a suspend so we can observe scheduling orders
            std::cout << "End inside spawn" << std::endl;
        }
#if NEWSTYLE
        , yield
#endif
    );
    std::cout << "End coro" << std::endl;
} catch(...) {
    std::cout << "Here be dragons" << std::endl;
}

int main() {
    std::cout << "Boost:" << BOOST_VERSION << " Asio:" << BOOST_ASIO_VERSION << std::endl;
    asio::spawn(ioctx.get_executor(), coro
#if NEWSTYLE
        , [](std::exception_ptr) { std::cout << "Exceptional" << std::endl; }
#endif
    );
    ioctx.run();
}

打印例如

Boost:107900 Asio:102202
Start coro
Spawn inside spawn
End coro
End inside spawn

VS.

Boost:108300 Asio:102802
Start coro
Spawn inside spawn
End inside spawn
Segmentation fault (core dumped)

最后,我确保通过仅切换 ASIO 版本而不是所有 boost 来将其隔离到仅 Asio 的更改:

我建议在 https://github.com/boostorg/asio/issues 或(可能更好?)https://github.com/chriskohlhoff/asio/issues

提出这个问题
© www.soinside.com 2019 - 2024. All rights reserved.