我同时使用了 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。
我认为您遇到了 Asio 1.24/Boost 1.80.0 中引入的错误。
我注意到提交发生了行为变化5bbdc9b添加了新的spawn()重载,符合异步操作的要求before1并在之前和之后进行了检查。
我无法给出满意的建议。我可以向您展示我所尝试过的内容(基于您最后一个最简单的示例)。
所有替代方案(例如继承内部 coro 的
yield
上下文,该上下文已被弃用但仍然存在)都不起作用。另请注意,旧样式实际上并没有达到相同的结果,因为无论 spawn
上下文是否继承,内部 yield
都不是“等待”的。 ́\(ツ)/́ 我想这使它“不是一个重大改变”,因为该功能在 Asio 1.24 之前并不存在。
注意,我还尝试向内部处理程序添加工作防护,但没有什么区别。
#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
提出这个问题