如何等待带有Boost ::: Asio的函数返回? [英] How to wait for a function to return with Boost:::Asio?

查看:52
本文介绍了如何等待带有Boost ::: Asio的函数返回?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对使用Boost :: Asio库是陌生的,并且无法获得我想要的行为.我正在尝试为自定义硬件解决方案实现一些网络通信.我们正在使用的通信协议栈在很大程度上依赖于Boost :: Asio异步方法,我不认为它是完全线程安全的.

I'm new to using Boost::Asio library and am having trouble getting the behaviour I want. I am trying to implement some network communication for custom hardware solution. The communication protocol stack we are using relies heavily on Boost::Asio async methods and I don't believe it is entirely thread safe.

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

I have successfully implemented sending but encountered a problem when trying to setup the await for receiving. Most boost::asio examples I have found rely on socket behaviour to implement async await with socket_.async_read_some() or other similar functions. However this doesn't work for us as our hardware solution requires calling driver function directly rather than utilising sockets.

应用程序使用 io_service ,该代码将传递到 boost :: asio :: generic :: raw_protocol :: socket 以及其他类中.

The application uses an io_service that is passed into boost::asio::generic::raw_protocol::socket as well as other classes.

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

This is the example code from the protocol stack. do_receive() is called in the constructor of RawSocketLink.

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()函数并等待其返回.这是一个阻塞的调用,但需要返回数据.

Our previous receive code without the protocol stack

Prior to implementing the stack we had been using the threading library to create separate threads for send and recieve. The receive method is shown below. Mostly it relies on calling the receive_data() function from the hardware drivers and waiting for it to return. This is a blocking call but is required to return data.

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;
}

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

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

This is my current code and where I need help. I'm not sure how to use boost::asio method to wait for receive_data to return. We are trying to replicate the behaviour of socket.async_read_from(). The NetworkAdapter has access to the 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函数来等待函数返回?特别是我想使用功能而不是套接字来复制 socket.async_receive_from()的行为.

*由于数据保护的要求,某些功能名称和类型已更改.

推荐答案

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

N4045 Library Foundations for Asynchronous Operations, Revision 2
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4045.pdf

第24页有一个示例,说明了如何基于基于回调的os API来实现asio异步API.

On page 24 there is an example on how to implement an asio async API in terms of callback-based os 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_completion handler_type 更改为 async_result ,因此上述代码已过时.

boost.asio has changed from async_completion and handler_type to async_result, so the above code is outdated.

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

Requirements on asynchronous operations - 1.75.0 https://www.boost.org/doc/libs/1_75_0/doc/html/boost_asio/reference/asynchronous_operations.html

这篇关于如何等待带有Boost ::: Asio的函数返回?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆