在这个复杂的例子中,两个for循环由boost :: asio :: spawn()异步启动。第一个for循环每1000us打印一个奇数,第二个每1000us打印一个偶数。
我希望输出类似于1 2 3 4 5 6,然后输出错误'应通过调用cerr将消息打印到stderr。
但是,异常实际上是在loop.run()中引发的,所以它不会被try catch块捕获。
有人可以指出在调用spawn()时如何正确捕获runtime_error吗? spawn()不会将生成的协程中抛出的异常重新加到其父作用域吗?
using namespace std;
using namespace boost::asio;
using boost::posix_time::microseconds;
io_service loop;
spawn(loop, [&loop](yield_context yield)
{
try
{
spawn(loop, [&loop](yield_context yield)
{
deadline_timer timer{loop};
for(unsigned i = 0; i < 3; ++i)
{
cout << i * 2 + 1 << endl;
timer.expires_from_now(microseconds(1000));
timer.async_wait(yield);
}
throw runtime_error("Throw an error");
});
spawn(loop, [&loop](yield_context yield)
{
deadline_timer timer{loop};
for(unsigned i = 0; i < 3; ++i)
{
cout << (i + 1) * 2 << endl;
timer.expires_from_now(microseconds(1000));
timer.async_wait(yield);
}
});
} catch(const runtime_error& ex)
{
cerr << ex.what() << endl;
}
});
loop.run();
答案 0 :(得分:1)
所有处理程序都由服务循环调用,这意味着您始终需要处理错误:Should the exception thrown by boost::asio::io_service::run() be caught?
旁注:在协同程序的情况下,我的经验是通过引用捕获有点棘手。这很可能与协程栈本身的生命周期有关。
您可以使用以下方式演示:
while (true) {
try {
loop.run();
break;
} catch(std::runtime_error ex) {
std::cerr << "L:" << __LINE__ << ": " << ex.what() << "\n";
}
}
请注意,传递error_code
错误可以通过两种方式在惯用的Asio界面中完成,包括Coroutines:How to set error_code to asio::yield_context
简单地使您的样品适应自我:
<强> Live On Coliru 强>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/high_resolution_timer.hpp>
using namespace std::chrono_literals;
int main() {
boost::asio::io_service loop;
spawn(loop, [&loop](boost::asio::yield_context yield)
{
try
{
spawn(yield, [&loop](boost::asio::yield_context yield)
{
boost::asio::high_resolution_timer timer{loop};
for(unsigned i = 0; i < 3; ++i)
{
std::cout << i * 2 + 1 << std::endl;
timer.expires_from_now(100ms);
timer.async_wait(yield);
}
throw std::system_error(ENOENT, std::system_category(), "Throw an error");
//throw boost::system::system_error(ENOENT, boost::system::system_category(), "Throw an error");
});
spawn(yield, [&loop](boost::asio::yield_context yield)
{
boost::asio::high_resolution_timer timer{loop};
for(unsigned i = 0; i < 3; ++i)
{
std::cout << (i + 1) * 2 << std::endl;
timer.expires_from_now(100ms);
timer.async_wait(yield);
}
});
} catch(const std::runtime_error& ex)
{
std::cerr << "L:" << __LINE__ << ": " << ex.what() << "\n";
}
});
while (true) {
try {
loop.run();
break;
} catch(std::runtime_error ex) {
std::cerr << "L:" << __LINE__ << ": " << ex.what() << "\n";
}
}
}
打印
1
2
3
4
5
6
L:49: Throw an error: No such file or directory
使用广义竞争令牌async_result
进行额外的处理:
<强> Live On Coliru 强>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/high_resolution_timer.hpp>
using namespace std::chrono_literals;
boost::asio::io_service loop;
template <typename Token>
auto async_foo(bool success, Token&& token)
{
typename boost::asio::handler_type<Token, void(boost::system::error_code, int)>::type
handler (std::forward<Token> (token));
boost::asio::async_result<decltype (handler)> result (handler);
boost::asio::yield_context yield(token);
boost::asio::high_resolution_timer timer{loop};
for(unsigned i = 0; i < 3; ++i) {
std::cout << (i * 2 + (success?0:1)) << std::endl;
timer.expires_from_now(100ms);
timer.async_wait(yield);
}
if (success)
handler(42);
else
throw boost::system::system_error(ENOENT, boost::system::system_category(), "Throw an error");
return result.get();
}
int main() {
auto spawn_foo = [](bool success) {
spawn(loop, [=](boost::asio::yield_context yield) {
try
{
int answer = async_foo(success, yield);
std::cout << "async_foo returned " << answer << std::endl;
} catch(const std::runtime_error& ex)
{
std::cerr << "L:" << __LINE__ << ": " << ex.what() << std::endl;
}
});
};
spawn_foo(true);
spawn_foo(false);
loop.run();
}
打印
0
1
2
3
4
5
async_foo returned 42
L:45: Throw an error: No such file or directory