Transferred from: https://www.jianshu.com/p/d6ae8adb5914
brief introduction
boost::asio::io_context literally means the context of Io. It can be understood that any io of boost will involve an io_context, synchronizing IO will implicitly start an io_context, and asynchronous IO requires us to specify one, and then call IO at the right time_ The context:: run() function will then enter the IO event loop. If IO is completed, the callback function will be called to ensure the implementation of relevant functions According to the official documentation, the IO has been started_ In the case of context:: run(), if there is no IO operation at this time, then io_context will automatically cancel the event loop, so if there is another asynchronous IO callback at this time, it will not work Refer to the following code:
#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(); // This function will also fail, but the callback function will not be called at this time, because the event loop of run has ended sock1.async_connect(ep, [](const boost::system::error_code & err) { if (err.value() != 0) { std::cout << err.message() << std::endl; } }); return 0; } /* Only one connection rejected message will be output, and the callback function of sock1 will not be called */
However, in some cases, we hope that the event loop of the run() function will not exit the event loop without io events, but wait all the time. When there are new asynchronous io calls, we can continue to use the loop
In the above code, it means that the callback function of asynchronous connection of sock1 can also be used
Concrete implementation
You need to use boost::asio::io_context::work. The core function of this class is to prevent io_context exits without IO event.
Direct use:
boost::asio::io_context::work(boost::asio::io_context & io_context);
When the work object is destroyed, its function will stop automatically The code description is given below
Code example:
#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)); // This is to prevent the callback from starting too fast 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"; // This is to prevent stop() from executing too fast std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "Main thread weak up...\n"; ioc.stop(); // Explicitly stop IO first_ Context, otherwise it cannot be terminated t.join(); return 0; }
Normal output:
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...
If boost:: ASIO:: IO is commented out_ context::work worker(ioc); This sentence will output:
Main thread will for 1 seconds... Main thread weak up... Main thread will for 1 seconds... Main thread weak up...
In other words, the event loop ends automatically without IO events
summary
When you are not sure that the IO asynchronous event callback occurs, if you want IO_ The context event loop keeps going. You can use boost::asio::io_context::work worker(ioc); To execute, you need to start a new thread to execute IO events. For details, refer to the above code