Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost ASIO: Asynchronous write, synchronously

I have a program (client + server) that works with no issue with this write:

boost::asio::write(this->socket_, boost::asio::buffer(message.substr(count,length_to_send)));

where socket_ is boost::asio::ssl::stream<boost::asio::ip::tcp::socket> and message is an std::string.

I would like to make this better and non-blocking, so I created a function that could replace this, it's called like follows:

write_async_sync(socket_,message.substr(count,length_to_send));

The purpose of this function is:

  1. To make the call async, intrinsically
  2. To keep the interface unchanged

The function I implemented simply uses promise/future to simulate sync behavior, which I will modify later (after it works) to be cancellable:

std::size_t 
SSLClient::write_async_sync(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>& socket, 
                            const std::string& message_to_send)
{
    boost::system::error_code write_error;
    std::promise<std::size_t> write_promise;
    auto write_future = write_promise.get_future();

    boost::asio::async_write(socket,
                             boost::asio::buffer(message_to_send), 
        [this,&write_promise,&write_error,&message_to_send]
        (const boost::system::error_code& error,
        std::size_t size_written)
        {
            logger.write("HANDLING WRITING");
            if(!error)
            {
                write_error = error;
                write_promise.set_value(size_written);
            }
            else
            {
                write_promise.set_exception(std::make_exception_ptr(std::runtime_error(error.message())));
            }
        });
    std::size_t size_written = write_future.get();
    return size_written;
}

The problem: I'm unable to get the async functionality to work. The sync one works fine, but async simply freezes and never enters the lambda part (the writing never happens). What am I doing wrong?


Edit: I realized that using poll_one() makes the function execute and it proceeds, but I don't understand it. This is how I'm calling run() for io_service (before starting the client):

io_service_work = std::make_shared<boost::asio::io_service::work>(io_service);
io_service_thread.reset(new std::thread([this](){io_service.run();}));

where basically these are shared_ptr. Is this wrong? Does this way necessitate using poll_one()?

like image 919
Sam Markus Avatar asked May 19 '17 18:05

Sam Markus


1 Answers

Re. EDIT:

You have the io_service::run() correctly. This tells me you are blocking on the future inside a (completion) handler. That, obviously, prevents run() from progressing the event loop.


The question asked by @florgeng was NOT whether you have an io_service instance.

The question is whether you are calling run() (or poll()) on it suitably for async operations to proceed.

Besides, you can already use future<> builtin:

  • http://www.boost.org/doc/libs/1_64_0/doc/html/boost_asio/overview/cpp2011/futures.html
  • Example: http://www.boost.org/doc/libs/1_64_0/doc/html/boost_asio/example/cpp11/futures/daytime_client.cpp
std::future<std::size_t> recv_length = socket.async_receive_from(
      boost::asio::buffer(recv_buf),
      sender_endpoint,
      boost::asio::use_future);
like image 156
sehe Avatar answered Nov 04 '22 01:11

sehe