繁体   English   中英

如何等待 function 返回 Boost:::Asio?

[英]How to wait for a function to return with Boost:::Asio?

背景

我是使用 Boost::Asio 库的新手,并且无法获得我想要的行为。 我正在尝试为自定义硬件解决方案实施一些网络通信。 我们使用的通信协议栈严重依赖于 Boost::Asio 异步方法,我不相信它是完全线程安全的。

我已成功实现发送,但在尝试设置等待接收时遇到问题。 我发现的大多数boost::asio 示例都依赖于套接字行为来使用socket_.async_read_some()或其他类似函数来实现异步等待。 但是这对我们不起作用,因为我们的硬件解决方案需要直接调用驱动程序 function 而不是使用 sockets。

该应用程序使用传递给boost::asio::generic::raw_protocol::socket以及其他类的io_service

使用 sockets 的协议栈示例代码

这是来自协议栈的示例代码。 在 RawSocketLink 的构造函数中调用do_receive()

void RawSocketLink::do_receive()
{
    namespace sph = std::placeholders;
    socket_.async_receive_from(
            boost::asio::buffer(receive_buffer_), receive_endpoint_,
            std::bind(&RawSocketLink::on_read, this, sph::_1, sph::_2));
}

void RawSocketLink::on_read(const boost::system::error_code& ec, std::size_t read_bytes)
{
    if (!ec) {
        // Do something with received data...
        do_receive();
    }
}

我们之前没有协议栈的接收代码

在实现堆栈之前,我们一直在使用线程库为发送和接收创建单独的线程。 接收方法如下所示。 大多数情况下,它依赖于从硬件驱动程序调用receive_data() function 并等待它返回。 这是一个阻塞调用,但需要返回数据。

void NetworkAdapter::Receive() {

  uint8_t temp_rx_buffer[2048];
  rc_t rc;
  socket_t *socket_ptr;
  receive_params_t rx_params;
  size_t rx_buffer_size;
  char str[100];

  socket_ptr = network_if[0];

  while (1) {
    rx_buffer_size = sizeof(temp_rx_buffer);
    // Wait until receive_data returns then process
    rc = receive_data(socket_ptr,
                     temp_rx_buffer,
                     &rx_buffer_size,
                     &rx_params,
                     WAIT_FOREVER);
    if (rc_error(rc)) {
      (void)fprintf(stderr, "Receive failed");
      continue;
    }
    
    // Do something with received packet ....
    
  }

  return;
}

请注意,此代码socket_t指针与 Boost::Asio 的 TCP/UDP 套接字不同。

异步接收的当前实现

这是我当前的代码,我需要帮助。 我不确定如何使用 boost::asio 方法等待 receive_data 返回。 我们正在尝试复制socket.async_read_from()的行为。 NetworkAdapter 可以访问io_service

void NetworkAdapter::do_receive() {
  
  rc_t rc;
  socket_t *socket_ptr;
  receive_params_t rx_params;
  size_t rx_buffer_size;

  socket_ptr = network_if[0];

  rx_buffer_size = receive_buffer_.size();
  
  // What do I put here to await for this to return asynchronously?
  rc = receive_data(socket_ptr, receive_buffer_.data(), &rx_buffer_size, &rx_params, ATLK_WAIT_FOREVER);
  on_read(rc, rx_buffer_size, rx_params);
}

void NetworkAdapter::on_read(const rc_t &rc, std::size_t read_bytes, const receive_params_t &rx_params) {
  if (!rc) {

    // Do something with received data...

  } else {
    LOG(ERROR) << "Packet receieve failure";
  }
  do_receive();
}

概括

如何使用 boost::asio async/await 函数等待 function 返回? 特别是我想复制socket.async_receive_from()的行为,但使用 function 而不是套接字。


*由于数据保护要求,某些 function 名称和类型已更改。

N4045 异步操作库基础,修订版 2
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf

在第 24 页上,有一个关于如何根据基于回调的操作系统 API 实现 asio 异步 API 的示例。

// the async version of your operation, implementing all kinds of async paradigm in terms of callback async paradigm
template <class CompletionToken>
auto async_my_operation(/* any parameters needed by the sync version of your operation */, CompletionToken&& token) 
{
  // if CompletionToken is a callback function object, async_my_operation returns void, the callback's signature should be void(/* return type of the sync version of your operation, */error_code)
  // if CompletionToken is boost::asio::use_future, async_my_operation returns future</* return type of the sync version of your operation */>
  // if CompletionToken is ..., ...

  // you are not inventing new async paradigms so you don't have to specialize async_completion or handler_type, you should focus on implement the os_api below
  async_completion<CompletionToken, void(/* return type of the sync version of your operation, */error_code)/* signature of callback in the callback case */> completion(token); 
  typedef handler_type_t<CompletionToken, void(error_code)> Handler; 
  unique_ptr<wait_op<Handler>> op(new wait_op<Handler>(move(completion.handler))); // async_my_operation initates your async operation and exits, so you have to store completion.handler on the heap, the completion.handler will be invoked later on a thread pool (e.g. threads blocked in IOCP if you are using os api, threads in io_context::run() if you are using asio (sockets accept an io_context during construction, so they know to use which io_context to run completion.handler))
  
  // most os api accepts a void* and a void(*)(result_t, void*) as its C callback function, this is type erasure: the void* points to (some struct that at least contains) the C++ callback function object (can be any type you want), the void(*)(result_t, void*) points to a C callback function to cast the void* to a pointer to C++ callback function object and call it
  os_api(/* arguments, at least including:*/ op.get(), &wait_callback<Handler>);

  return completion.result.get();
}

// store the handler on the heap
template <class Handler>
struct wait_op {
  Handler handler_;
  explicit wait_op(Handler  handler) : handler_(move(handler)) {}
};

// os post a message into your process's message queue, you have several threads blocking in a os api (such as IOCP) or asio api (such as io_context::run()) that continuously takes message out from the queue and then call the C callback function, the C callback function calls your C++ callback function
template <class Handler> 
void wait_callback(result_t result, void* param) 
{
  unique_ptr<wait_op<Handler>> op(static_cast<wait_op<Handler>*>(param));
  op‐>handler_(/* turn raw result into C++ classes before passing it to C++ code */, error_code{});
}

//trivial implementation, you should consult the socket object to get the io_context it uses
void os_api(/* arguments needed by your operation */, void* p_callback_data, void(*p_callback_function)(result_t, void*))
{
  std::thread([](){
    get the result, blocks
    the_io_context_of_the_socket_object.post([](){ (*p_callback_function)(result, p_callback_data); });
  }).detach();
}

boost.asio 已经从async_completionhandler_type更改为async_result ,所以上面的代码已经过时了。

异步操作要求 - 1.75.0 https://www.boost.org/doc/libs/1_75_0/doc/html/boost_asio/reference/asynchronous_operations.html

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM