【问题标题】:boost::asio::async_write_some - sequential function callboost::asio::async_write_some - 顺序函数调用
【发布时间】:2021-06-15 19:38:37
【问题描述】:

我正在使用 boost.asio 编写应用程序。我有一个boost::asio::ip::tcp::socket 类型的对象,(当然)我有boost::asio::io_context,其中run 的函数仅从一个线程调用。将数据写入套接字有几种方法,但目前我使用套接字的函数async_write_some,类似于下面的代码:

void tcp_connection::write(packet_ptr packet)
{
    m_socket.async_write_some(boost::asio::buffer(packet->data(), packet->size()),
                              std::bind(&tcp_connection::on_write, this, std::placeholders::_1, std::placeholders::_2, packet));
}

boost::asio 命名空间中还有另一个函数 - async_writeasync_write 的文档说:

此操作通过对流的 async_write_some 函数的零次或多次调用来实现,称为组合操作。在此操作完成之前,程序必须确保流不执行其他写入操作(例如 async_write、流的 async_write_some 函数或任何其他执行写入的组合操作)。

async_write_some 的文档中没有这种“警告”。

这让我有点困惑,在这里我有以下问题:

  1. 在不等待上一次通话结束的情况下拨打async_write_some 是否安全?据我从 boost 的文档中了解到,我不应该对 async_write 这样做,但是 async_write_some 呢?
  2. 如果是,数据写入套接字的顺序是否与调用函数的顺序相同?我的意思是,如果我调用 async_write_some(packet1)async_write_some(packet2) - 数据包是否会以相同的顺序写入套接字?
  3. 我应该使用哪个函数?它们有什么区别?
  4. 上一个电话还没打完,打async_write不安全是什么原因?

【问题讨论】:

    标签: c++ boost boost-asio


    【解决方案1】:
    1. 不;其原因可能记录在底层套接字 API (BSD/WinSock) 中。

    2. 不适用。请注意,调用处理程序的顺序保证与发布它们的顺序相匹配,因此您可以使用async_write_some 调用的异步链来解决它,其中完成处理程序发布下一次写入.这称为隐式链(参见https://www.boost.org/doc/libs/master/doc/html/boost_asio/overview/core/async.htmlWhy do I need strand per connection when using boost::asio?)。

    3. 99% 的时间,使用免费功能。不同之处在于它实现了组合操作来发送一个“单元”信息,即整个缓冲区、消息,或者直到满足给定的完成条件。

      async_write_some 是最低级别的构建块,它甚至不能保证写入所有数据:remarks

      写入操作可能不会将所有数据传输到对等方。 如果您需要确保所有 在异步操作完成之前写入数据。

    4. 从最严格的意义上说,这并不是不安全的¹。它只是不会导致正确的结果:这是因为调用处理程序的顺序导致数据以混合顺序写入套接字。


    ¹(除非您在不同步的情况下同时访问共享 IO 对象)

    【讨论】:

    • 感谢您的回复。 boost::asio::io_context 保证我的处理程序将仅由调用 run 函数的线程执行。但这仅适用于处理程序,不是吗?我是否正确 boost::asio::io_context 可以同时执行两个写操作?
    • 不是因为你只在一个线程上运行它。否则,是的,处理程序可能会同时运行,您必须做出规定(例如使用链)
    • 谢谢,我想我很清楚处理程序是如何被调用的。但是您能否澄清一下 - 即使我只从一个线程调用 run,异步任务也可能在不同的线程上执行?如果我调用 async_write 两次,io_context 可能会在两个不同的线程上执行它们,这就是我应该同步它们的原因?
    • 不,它们是异步运行的,通常使用库/内核级别的异步接口。在实践中,这意味着(子)操作的完成可能是交错的。与其说是“同步”,不如说是“序列化(执行)”或“序列化”。
    • 简而言之,虽然并发和异步是正交的概念,但它们有一些复杂的问题——原因略有不同。
    猜你喜欢
    • 2016-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-30
    • 1970-01-01
    • 2020-11-06
    • 1970-01-01
    相关资源
    最近更新 更多