boost::asio::spawn 中的异常抛出未被 try catch 捕获
Exception throw in boost::asio::spawn not caught by try catch
在这个复杂的示例中,两个 for 循环由 boost::asio::spawn() 异步启动。第一个 for 循环每 1000us 打印一个奇数,第二个 for 循环每 1000us 打印一个偶数。
我希望输出类似于 1 2 3 4 5 6,然后应该通过调用 cerr 将 'Throw an error' 消息打印到 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();
所有处理程序都由服务循环调用,这意味着您始终需要处理错误:Should the exception thrown by boost::asio::io_service::run() be caught?
Sidenote: In the case of coroutines, it's my experience that catching by reference is a bit tricky. This more than likely has to do with the lifetime of the coroutine stack itself.
您可以使用以下方式进行演示:
while (true) {
try {
loop.run();
break;
} catch(std::runtime_error ex) {
std::cerr << "L:" << __LINE__ << ": " << ex.what() << "\n";
}
}
其他注意事项
请注意,传递 error_code
错误可以通过惯用的 Asio 接口以两种方式完成,包括协程:How to set error_code to asio::yield_context
完整样本
简单地调整您的样本以使其独立:
#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
:
进行额外的处理
#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
在这个复杂的示例中,两个 for 循环由 boost::asio::spawn() 异步启动。第一个 for 循环每 1000us 打印一个奇数,第二个 for 循环每 1000us 打印一个偶数。
我希望输出类似于 1 2 3 4 5 6,然后应该通过调用 cerr 将 'Throw an error' 消息打印到 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();
所有处理程序都由服务循环调用,这意味着您始终需要处理错误:Should the exception thrown by boost::asio::io_service::run() be caught?
Sidenote: In the case of coroutines, it's my experience that catching by reference is a bit tricky. This more than likely has to do with the lifetime of the coroutine stack itself.
您可以使用以下方式进行演示:
while (true) {
try {
loop.run();
break;
} catch(std::runtime_error ex) {
std::cerr << "L:" << __LINE__ << ": " << ex.what() << "\n";
}
}
其他注意事项
请注意,传递 error_code
错误可以通过惯用的 Asio 接口以两种方式完成,包括协程:How to set error_code to asio::yield_context
完整样本
简单地调整您的样本以使其独立:
#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
:
#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