boost::asio 拥有“ConstBufferSequence”的数据

boost::asio data owning `ConstBufferSequence`

最后几天,我阅读了很多 asio 示例和其他有关传递给 asios 启动函数的缓冲区的生命周期管理的问题。一个让我印象深刻的问题是,似乎没有“按值”解决方案,而是发起函数的调用者始终需要确保缓冲区有效,直到异步操作完成。这通常是通过创建指向数据的共享指针并将它们复制到处理程序中来实现的。

在我的例子中,我已经在使用 async_write 重载,其中传递了一个 ConstBufferSequence,例如下一条消息的大小后跟下一条消息。即

auto message = std::make_shared<std::string>("hello");
auto size = std::make_shared<std::uint32_t>(message.size());
std::vector<asio::const_buffer> buffers = {asio::buffer(size, sizeof(*size)), asio::buffer(*message)};
asio::async_write(_socket, buffers, [message,size](...){...}); // prolong lifetime by coping shared ptrs.

所以我正在考虑编写一个自定义 Message class 来实现 ConstBufferSequence 概念,同时 拥有 底层消息。我深入研究了代码,发现在一个地方,缓冲区序列参数首先通过 const& 传递到 asio::async_write,然后通过 const& 传递到最后复制到asio::detail::write_opclass.

的成员变量中

这里是实际问题:

好奇大家的想法~欢迎批评指正! ;-)

此致,马丁

以前看过一个shared_buffer(我想是在Asiodocs/exmples里面的,以后再找)。

而且显然还有

  • boost::asio::streambuf
  • Beast缓冲模型(flat_buffer, multi_buffer, vector_buffer)

当然,这只是把问题从所有权问题变成了生命周期问题。

将 Boost Asio 的缓冲区概念设为“ref-only”或“view-semantics”的好处是

  • 你永远不会 运行 遇到按值传递这些引用的生命周期问题,并且
  • 它们非常适合以正确的方式实施组合操作:无需对缓冲区组织进行假设

找到Asio例子:https://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/example/buffers/reference_counted.cpp这几天住在

  • example/cpp03/buffers/reference_counted.cpp
  • example/cpp11/buffers/reference_counted.cpp

解决问题

Can this approach work for a fire and forget call? This would translate above intos something like: asio::async_write(_socket, Message("hello"),{});

Are there any issues with the lifetime of the constbuffer sequence arguments w.r.t. composed operations?

如果你管理得好就不会,无论如何这是一个要求

Would this be a good idea? It obviously goes against the "normal" asio way of dealing with buffer lifetime management.

取决于你怎么做。如果您最终批量复制缓冲区,那将是昂贵的,并且也不适用于某些异步操作(这需要缓冲区具有 引用稳定性 ,意思是:不更改地址,在换句话说,不要四处走动)。

通过移动语义,许多缓冲区类型可能仍然能够提供此功能 属性,但按值传递缓冲区的问题在于它们可能会制作多个副本,

  • 两者都不编译(因为它们不是右值)
  • 或者(如果你用移动副本破解它 constructor/assignment)当使用移动副本时可能会导致 UB