簡體   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