代码之家  ›  专栏  ›  技术社区  ›  doraemon

boost中的异常抛出::asio::try catch未捕获到spawn

  •  1
  • doraemon  · 技术社区  · 7 年前

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

    我希望输出类似于1 2 3 4 5 6,然后通过调用cerr将“抛出错误”消息打印到stderr。

    然而,异常实际上是在循环中抛出的。run()使其不被try-catch块捕获。

    有人能指出在调用spawn()时如何正确捕获runtime\u错误吗?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();
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   sehe    7 年前

    所有处理程序都由服务循环调用,这意味着您始终需要处理错误: 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接口执行错误,包括协同路由: 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