[英]Use of Boost.Coroutine with Boost.ASIO causes assertion
我有boost :: asio :: io_context在多個線程中運行(通過ctx.run()),我在boost.coroutines中使用了幾個異步對象,這些對象通過boost :: asio :: spawn運行。 我有以下斷言:
Assertion failed: ! is_running(), file C:\boost\boost_1_68_0\msvc_x86\include\boost-1_68\boost\coroutine\detail\push_coroutine_impl.hpp, line 258
我正在提供一個導致相同錯誤的最小示例。 請幫幫我:我在做什么錯?
Boost版本是1.68
[更新]:代碼中有一個修復程序(忘記鎖定io_context),但是無論如何它不會影響斷言。
#include <iostream>
#include <thread>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
template<class CompletionToken>
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(boost::system::error_code))
asyncDo(boost::asio::io_context& ctx, CompletionToken&& token)
{
using CompletionType = boost::asio::async_completion<CompletionToken, void(boost::system::error_code)>;
CompletionType completion{ token };
ctx.post(
[handler{ completion.completion_handler }](){
using boost::asio::asio_handler_invoke;
asio_handler_invoke(std::bind(handler, boost::system::error_code()), &handler);
return;
});
return completion.result.get();
}
void coroFunc(boost::asio::io_context& ctx, boost::asio::yield_context yield)
{
for (;;) {
std::cerr << std::this_thread::get_id() << '\n';
asyncDo(ctx, yield);
std::cerr << std::this_thread::get_id() << '\n';
}
}
int main(int, char* [])
{
boost::asio::io_context ctx;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work(ctx.get_executor());
boost::asio::spawn(ctx, std::bind(coroFunc, std::ref(ctx), std::placeholders::_1));
std::thread([&ctx]() { ctx.run(); }).detach();
std::thread([&ctx]() { ctx.run(); }).detach();
std::cin.get();
work.reset();
return 0;
}
經過數小時的谷歌搜索和嘗試,我找到了適合我的解決方案(至少在我的測試中)。 主要思想是將發布到ctx替換為發布到關聯的執行者 :
auto executor = boost::asio::get_associated_executor(completion.completion_handler, ctx);
auto allocator = boost::asio::get_associated_allocator(completion.completion_handler);
executor.post(
[handler = HandlerType{ std::move(completion.completion_handler) }](){
using boost::asio::asio_handler_invoke;
asio_handler_invoke(std::bind(handler, boost::system::error_code()), &handler);
return;
},
allocator);
整個代碼:
#include <iostream>
#include <stdexcept>
#include <thread>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
template<class CompletionToken>
BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void(boost::system::error_code))
asyncDo(boost::asio::io_context& ctx, CompletionToken&& token)
{
using CompletionType = boost::asio::async_completion<CompletionToken, void(boost::system::error_code)>;
using HandlerType = typename CompletionType::completion_handler_type;
CompletionType completion{ token };
auto executor = boost::asio::get_associated_executor(completion.completion_handler, ctx);
auto allocator = boost::asio::get_associated_allocator(completion.completion_handler);
executor.post(
[handler = HandlerType{ std::move(completion.completion_handler) }](){
using boost::asio::asio_handler_invoke;
asio_handler_invoke(std::bind(handler, boost::system::error_code()), &handler);
return;
},
allocator);
return completion.result.get();
}
void coroFunc(boost::asio::io_context& ctx, boost::asio::yield_context yield)
{
for (;;) {
try {
std::cerr << "(0): " << std::this_thread::get_id() << '\n';
asyncDo(ctx, yield);
std::cerr << "(1): " << std::this_thread::get_id() << '\n';
} catch (std::exception const& e) {
std::cerr << "e: " << e.what() << '\n';
}
}
}
int main(int, char* [])
{
boost::asio::io_context ctx;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work(ctx.get_executor());
boost::asio::spawn(ctx, std::bind(coroFunc, std::ref(ctx), std::placeholders::_1));
std::thread([&ctx]() {
for (;;) {
try {
ctx.run();
break;
} catch (std::exception const& e) {
std::cerr << "e: " << e.what() << '\n';
}
}
}).detach();
std::thread([&ctx]() {
for (;;) {
try {
ctx.run();
break;
} catch (std::exception const& e) {
std::cerr << "e: " << e.what() << '\n';
}
}
}).detach();
std::cin.get();
work.reset();
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.