异常引发boost :: asio :: spawn没有被try catch捕获 [英] Exception throw in boost::asio::spawn not caught by try catch

查看:117
本文介绍了异常引发boost :: asio :: spawn没有被try catch捕获的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这个复杂的例子中,两个for循环由boost :: asio :: spawn()异步启动.第一个for循环每1000us打印一个奇数,第二个for循环每1000us打印一个偶数.

In this convoluted example, two for loops are started by boost::asio::spawn() asynchronously. The first for loop prints an odd number every 1000us and the second one prints an even number every 1000us.

我希望输出结果类似于1 2 3 4 5 6,然后应该通过调用cerr将"Throw a error"(抛出错误)消息打印到stderr.

I expect the output to be something like 1 2 3 4 5 6 and then the 'Throw an error' message should be printed to stderr by the call to cerr.

但是,异常实际上是在loop.run()中引发的,因此它不会被try catch块捕获.

However, the exception is actually thrown in loop.run() so it is not caught by the try catch block.

有人可以指出在调用spawn()时如何正确捕获runtime_error吗?spawn()是否不会将在生成的协程中引发的异常提升到其父作用域?

Can someone point out how to properly catch the runtime_error when calling spawn()? Does spawn() not reraise the exception thrown in the spawned coroutine to its parent scope?

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();

推荐答案

所有处理程序均由服务循环调用,这意味着您始终需要处理错误:

All handlers are invoked by the service loop, meaning you always need to handle errors: 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.

您可以使用以下方法进行演示:

You can demonstrate it using:

while (true) {
    try {
        loop.run();
        break;
    } catch(std::runtime_error ex) {
        std::cerr << "L:" << __LINE__ << ": " << ex.what() << "\n";
    }
}

其他说明

请注意,在惯用的Asio接口(包括协程)中,可以通过两种方式来传递 error_code 错误:只需将您的样本调整为独立的即可:

Simply adapting your sample to be selfcontained:

在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 做额外的方法:

在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

这篇关于异常引发boost :: asio :: spawn没有被try catch捕获的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆