I'm trying to change the implementation of a fire-and-forget UDP send-function from being synchronous to asynchronous.
The current simplified synchronous function looks like this:
ssize_t UDPTransport::send_to(const char * buffer, size_t bufferSize) { return mPSocket->send_to(boost::asio::buffer(buffer, bufferSize), mOutputEndpoint); } I've got a thread_group set up and io_service::run() is set to use it. However, the problem is that I have no guarantee that buffer will exist after this call has completed. I need to store the contents of the buffer and then know when it is free so that I can re-use it later or delete it. The following is simple, but if I fire off two send_to calls, then I have no guarantee that the handle_send will be called in the same order and I might pop something that is still needed!
ssize_t UDPTransport::send_to(const char * buffer, size_t bufferSize) { boost::asio::mutable_buffer b1 = boost::asio::buffer(buffer,bufferSize); mMutex.lock(); mQueue.push(b1); mPSocket->async_send_to(mQueue.back(), mOutputEndpoint, boost::bind(&UDPTransport::handle_send, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); mMutex.unlock(); return bufferSize; } void UDPTransport::handle_send(const boost::system::error_code& error, std::size_t bytes_transferred) { mMutex.lock(); mQueue.pop(); mMutex.unlock(); } What's a good way to store an asynchronous buffer, then clean it up once it's no longer needed?
Reading online an even simpler way may be below, but I don't know if I trust it. Why would a shared pointer decide to not de-allocate itself until after the handler has been called?
ssize_t UDPTransport::send_to(const char * buffer, size_t bufferSize) { auto buf = std::make_shared<std::string>(buffer, bufferSize); mPSocket->async_send_to(boost::asio::buffer(*buf), mOutputEndpoint, boost::bind(&UDPTransport::handle_send, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); return bufferSize; }