views:

319

answers:

1

I couldn't find any thing about what happens if you try to do a second write to a boost::asio socket before a previous one completed. This seems like something that could potentially happen in many asynchronous programs (since after doing the first write, the program will then continue before waiting for it to finish, potentially causing a second message to be sent and so on). I've thought of a few possible things that could happen (this is assuming that in all cases the message is sent with a single call to async_write).

void handleWrite(const boost::system::error_code&error)
{
    if(error)throw NetError(error);
}

vodi sendStuff()
{
    const char msg1 = "Red, Green, Blue";
    const char msg2 = "One, Two, Three";

    asio::async_write(socket,asio::buffer(msg1,sizeof(msg1)),boost::bind(&handleWrite,_1));
    //assume msg1 has still not been sent by the time we get here
    asio::async_write(socket,asio::buffer(msg2,sizeof(msg2)),boost::bind(&handleWrite,_1));
}

So assuming that the first send doesn't cause an error:

  • Asio sends msg1, then msg2, in order, possible even in a single TCP packet
  • The second async_write call blocks until msg1 is done
  • The result is undefined

If an error occurs in msg1s, i'm assuming the exception will cause msg2 to abort as well?

Also is this effected by if the associated io_service has a thread pool, or just a single thread?

If it's not safe, then has any one written some kind of simple wrapper that maintains a queue of messages to send, sending them one by one and aborting if any write handler throws an exception?

+1  A: 

So, with normal non-blocking sockets, you can write some implementation-dependant amount of stuff to the socket, then eventually a write will return -EWOULDBLOCK and not do the write so you can retry later. Poking around in the source tells me that Boost wraps that, so that everything you write should get there eventually (or raise an error, not including would_block or try_again).

Andrew McGregor