Reputation: 53
I am confused about io_services object working mechanism. My understanding is that there is a queue associates with io_service object, if any async invocation will add one item in the queue, when io_service.run_once is called ,one async invocation will run and dequeue from the queue. if the queue is empty the io_service.run_one will do nothing until new invocation is added. I organized some code form the boost example but It seems that my understanding is wrong.
#include <boost/asio/connect.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/write.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
using boost::asio::deadline_timer;
using boost::asio::ip::tcp;
class client
{
public:
client()
: socket_(io_service_)
{
}
void connect_handler(const boost::system::error_code& error,boost::system::error_code *er)
{
std::cerr<<"connect handler"<<std::endl;
*er = error;
std::cerr<<error<<std::endl;
}
void connect(const std::string& host, const std::string& service)
{
tcp::resolver::query query(host, service);
tcp::resolver::iterator iter = tcp::resolver(io_service_).resolve(query);
std::cerr<<"connect start"<<std::endl;
boost::system::error_code ec = boost::asio::error::would_block;
boost::asio::async_connect(socket_, iter, bind(&client::connect_handler,this,_1,&ec));
do
{io_service_.run_one();
}while (ec == boost::asio::error::would_block);
//io_service_.reset(); // The write async will be stuck without this reset call.
std::cerr<<"connect done"<<std::endl;
if (ec || !socket_.is_open())
throw boost::system::system_error(
ec ? ec : boost::asio::error::operation_aborted);
}
void write_handler(const boost::system::error_code& error, std::size_t size,boost::system::error_code* er )
{
std::cerr<<"write handler "<<std::endl;
*er=error;
std::cerr<<error<<std::endl;
}
void write_line(const std::string& line)
{
std::cerr<<"write start"<<std::endl;
std::string data = line + "\n";
boost::system::error_code ec = boost::asio::error::would_block;
boost::asio::async_write(socket_, boost::asio::buffer(data), bind(&client::write_handler,this,_1,_2,&ec));
do
{
io_service_.run_one();
}while (ec == boost::asio::error::would_block);
std::cerr<<"write done";
if (ec)
throw boost::system::system_error(ec);
}
private:
boost::asio::io_service io_service_;
tcp::socket socket_;
};
int main()
{
try
{
client c,d;
c.connect("172.217.6.36", "80");// google IP.
c.write_line("example");
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
My understand is that:
Start
|
async_connect ----> add one item in io_service queue
|
|
io_serivce.run_one() ------> dequeue the async_connect call back from io_serivce queue
|
|
connect_handler --------> connect_handler called change the ec value
|
|
async_write ----------> add one item in io_service queue.
|
|
io_service.run_one()------------>dequeue the async_write call back from io_serivce queue
|
|
write_handler()----------------->write handler called and change the ec value
|
Done
but the reality is
Start
|
async_connect ----> add one item in io_service queue
|
|
io_serivce.run_one() ------> dequeue the async_connect call back from io_serivce queue
|
|
connect_handler --------> connect_handler called change the ec value
|
|
async_write ----------> add one item in io_service queue.
|
|
io_service.run_one()------------>stuck here in the while loop forever, the async_write handler is never be called the ec is never be changed.
Sehe told me that the io_service.reset needed to be called in another post, what I don't understand why io_service.reset needs to be called? the original example doesn't use this call and it works fine. With the reset call works:
Start
|
async_connect ----> add one item in io_service queue
|
|
io_serivce.run_one() ------> dequeue the async_connect call back from io_serivce queue
|
|
connect_handler --------> connect_handler called change the ec value
|
|
io_service.reset() --------> reset the io service.
|
|
async_write ----------> add one item in io_service queue.
|
|
io_service.run_one()------------>dequeue the async_write call back from io_serivce queue
|
|
write_handler()----------------->write handler called and change the ec value
|
Done
Upvotes: 1
Views: 234
Reputation: 393999
The original sample uses the deadline-timer which is in a continuous chain of async_waits
. This means that the io_service
will never run out of work.
That's it. The whole difference. If you let the service run out of work, run_*
will return and you will need to call reset()
before you can use the io_service
again.
See also Why must io_service::reset() be called?
For context the earlier answer boost socket example stuck in while loop where I give several better approaches to making this work either using synchronous calls or using asynchronous calls.
Upvotes: 1