C++ 为异步发送缓冲区保留内存(boost asio套接字)

C++ 为异步发送缓冲区保留内存(boost asio套接字),c++,sockets,boost,boost-asio,C++,Sockets,Boost,Boost Asio,我正在尝试将fire and forget UDP发送函数的实现从同步更改为异步 当前简化的同步功能如下所示: ssize_t UDPTransport::send_to(const char * buffer, size_t bufferSize) { return mPSocket->send_to(boost::asio::buffer(buffer, bufferSize), mOutputEndpoint); } 我已经设置了一个线程组,并且io\u service::

我正在尝试将fire and forget UDP发送函数的实现从同步更改为异步

当前简化的同步功能如下所示:

ssize_t UDPTransport::send_to(const char * buffer, size_t bufferSize) {
    return mPSocket->send_to(boost::asio::buffer(buffer, bufferSize), mOutputEndpoint);
}
我已经设置了一个
线程组
,并且
io\u service::run()
已设置为使用它。但是,问题是我不能保证在这个调用完成后,
缓冲区将存在。我需要存储缓冲区的内容,然后知道它什么时候是空闲的,以便以后可以重复使用或删除它。下面很简单,但是如果我发出两个
send\u-to
调用,那么我不能保证
handle\u-send
将以相同的顺序被调用,我可能会
pop
一些仍然需要的东西

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();
}
存储异步缓冲区,然后在不再需要时清理它的好方法是什么

下面可能是一个更简单的方法,但我不知道我是否相信它。为什么共享指针要在调用处理程序之前决定不取消自身分配

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;
}
ssize\u t udpttransport::发送到(const char*buffer,size\u t bufferSize)
{
自动buf=std::使_共享(缓冲区、缓冲区大小);
mPSocket->async_send_to(boost::asio::buffer(*buf),moutpundpoint,
boost::bind(&udpttransport::handle_send,这个,
boost::asio::占位符::错误,
boost::asio::占位符::字节(已传输);
返回缓冲区大小;
}

我通常做的是将其包装在一个继承自std::enable_shared_from_的类中,并遵循以下几行:

class Sender : public std::enable_shared_from_this<Sender> {
 public:
  using CompletionHandler =
      std::function<void(const boost::system::error_code& ec,
                         size_t bytes_transferred,
                         std::shared_ptr<Sender> sender)>;

  ~Sender() = default;

  template<typename... Args>
  static std::shared_ptr<Sender> Create(Args&&... args) {
    return std::shared_ptr<Sender>(new Sender(std::forward<Args>(args)...));
  }

  void AsyncSendTo(const char* buffer, size_t buffer_size,
                   CompletionHandler completion_handler) {
    data_.append(buffer, buffer_size);
    socket.async_send_to(
        boost::asio::buffer(data_), endpoint_,
        [self = shared_from_this(),
         completion_handler = std::move(completion_handler)]
        (const boost::system::error_code& ec,
         size_t bytes_transferred) mutable {
          completion_handler(ec, bytes_transferred, std::move(self));
        });
  }

 private:
  Sender() = default;
  Sender(const Sender&) = delete;
  Sender(Sender&&) = delete;
  Sender& operator=(const Sender&) = delete;
  Sender& operator=(Sender&&) = delete;

  SocketType socket_;
  EndpointType endpoint_;
  std::string data_;
}
类发送方:公共std::从\u中启用\u共享\u{
公众:
使用CompletionHandler=
std::函数;
~Sender()=默认值;
模板
静态std::共享\u ptr创建(Args&&…Args){
返回std::shared_ptr(新发送方(std::forward(args)…);
}
void AsyncSendTo(常量字符*缓冲区,大小\u t缓冲区大小,
CompletionHandler(完成处理程序){
数据追加(缓冲区、缓冲区大小);
socket.async\u发送到(
boost::asio::缓冲区(数据),端点,
[self=shared_from_this(),
完成处理程序=std::move(完成处理程序)]
(const boost::系统::错误代码和ec,
大小(传输的字节数)可变{
完成处理程序(ec,已传输字节,std::move(self));
});
}
私人:
Sender()=默认值;
发送方(const Sender&)=删除;
发送者(发送者&)=删除;
发送方和运算符=(const Sender&)=删除;
发送方和运算符=(发送方和运算符)=删除;
插座式插座;
端点类型端点;
std::字符串数据;
}
显然,您必须保证
完成处理程序的生命周期。但除此之外,无论何时完成,完成处理程序都会返回一个有效的
std::shared_ptr
,您可以对数据发送器执行任何需要的操作

在您发布的示例中,
buf
将离开作用域并在
send_to
return上被销毁,除非您首先在
bind
中捕获它

脚注1:可能需要删除那些
std::move()
s,这取决于编译器是否与lambdas兼容


脚注2:除非您绝对需要利用其动态特性,否则请远离
bind

您链接的共享\u ptr解决方案可能是正确的,因为它在lambda中按值捕获共享的\u ptr。因此,一旦调用了处理程序,它就应该释放自己。但是,您的共享ptr代码不能做到这一点。