美文网首页
boost::asio::io_context的事件循环

boost::asio::io_context的事件循环

作者: chjxidian | 来源:发表于2019-11-19 15:38 被阅读0次

    简介

    boost::asio::io_context看字面意思是io的上下文, 可以理解为, boost的任何io都会涉及到一个io_context, 同步io会隐式地启动一个io_context, 而异步io需要我们指定一个, 然后在合适的时机调用io_context::run()函数, 之后会进入io事件循环, 如果io完成会调用回调函数, 保证实现有关的功能. 根据官方文档, 在已经启动io_context::run()的情况下, 如果此时没有了io操作, 那么io_context会自动取消事件循环, 那么此时如果再有异步io回调, 也不会发生作用了. 参考下面的代码:

    #include <iostream>
    #include <boost/asio.hpp>
    
    std::string raw_ip_addr = "127.0.0.1";
    unsigned short port_num = 6768;
    
    int main() {
        boost::asio::io_context ioc;
        boost::asio::ip::tcp::endpoint
        ep(boost::asio::ip::address::from_string(raw_ip_addr), port_num);
        boost::asio::ip::tcp::socket sock(ioc, ep.protocol());
        boost::asio::ip::tcp::socket sock1(ioc, ep.protocol());
    
        sock.async_connect(ep, [](const boost::system::error_code & err) {
            if (err.value() != 0) {
                std::cout << err.message() << std::endl;
            }
        });
        ioc.run();
    
        // 这个函数也会失败, 但是此时不会其调用回调函数了, 因为run的事件循环已经结束了
        sock1.async_connect(ep, [](const boost::system::error_code & err) {
            if (err.value() != 0) {
                std::cout << err.message() << std::endl;
            }
        });
    
        return 0;
    }
    /*
    只会输出一个Connection refused消息, sock1的回调函数不会被调用
    */
    

    但是有些情况下, 我们希望run()函数的事件循环在没有io事件的情况下, 也不会退出事件循环, 而是一直等待, 当有了新的异步io调用的时候, 还可以继续使用该循环.

    放在上述的代码中, 意思就是sock1的异步连接的回调函数还可以使用

    具体实现
    需要借助boost::asio::io_context::work来实现, 这个类的核心左右就是防止io_context在没有io事件的情退出. 直接使用:

    boost::asio::io_context::work(boost::asio::io_context & io_context);
    

    的方式进行构造, 当work对象被销毁时, 它的作用就自动停止了.下面给出代码说明.

    代码示例:

    #include <iostream>
    #include <thread>
    #include <boost/asio.hpp>
    #include <chrono>
    
    std::string raw_ip_addr = "127.0.0.1";
    unsigned short port_num = 6768;
    
    int main() {
        boost::asio::io_context ioc;
        boost::asio::ip::tcp::endpoint
        ep(boost::asio::ip::address::from_string(raw_ip_addr), port_num);
        boost::asio::ip::tcp::socket sock(ioc, ep.protocol());
        boost::asio::ip::tcp::socket sock1(ioc, ep.protocol());
        boost::asio::ip::tcp::socket sock2(ioc, ep.protocol());
    
        boost::asio::io_context::work worker(ioc);
        std::thread t([&ioc](){ioc.run();});
    
        std::cout << "Main thread will for 1 seconds...\n";
        std::this_thread::sleep_for(std::chrono::seconds(1));  // 这里是防止回调启动过快
        std::cout << "Main thread weak up...\n";
    
        sock.async_connect(ep, [](const boost::system::error_code & err) {
            if (err.value() != 0) {
                std::cout << err.message() << std::endl;
            }
        });
    
        sock1.async_connect(ep, [](const boost::system::error_code & err) {
            if (err.value() != 0) {
                std::cout << err.message() << std::endl;
            }
        });
    
        sock2.async_connect(ep, [](const boost::system::error_code & err) {
            if (err.value() != 0) {
                std::cout << err.message() << std::endl;
            }
        });
    
        std::cout << "Main thread will for 1 seconds...\n";  // 这里是为了放置stop()执行过快
        std::this_thread::sleep_for(std::chrono::seconds(1));
        std::cout << "Main thread weak up...\n";
        ioc.stop();  // 先显式停止io_context, 否则无法终止
        t.join();
        return 0;
    }
    

    正常输出:

    Main thread will for 1 seconds...
    Main thread weak up...
    Main thread will for 1 seconds...
    Connection refused
    Connection refused
    Connection refused
    Main thread weak up...
    

    如果注释掉boost::asio::io_context::work worker(ioc);这一句, 那么会输出:

    Main thread will for 1 seconds...
    Main thread weak up...
    Main thread will for 1 seconds...
    Main thread weak up...
    

    也就是说, 事件循环在没有IO事件的情况下, 就自动结束了.

    总结

    在不确定io异步事件回调发生的情况下, 如果想要io_context事件循环一直进行, 可以使用boost::asio::io_context::work worker(ioc);来执行, 需要开启一个新的线程, 专门执行IO事件即可, 具体参考上述代码.

    参考资料

    ————————————————
    原文链接:https://blog.csdn.net/qq_35976351/article/details/90373124

    相关文章

      网友评论

          本文标题:boost::asio::io_context的事件循环

          本文链接:https://www.haomeiwen.com/subject/zczwictx.html