`std::async` 用于 C++ 中的异步回复

`std::async` for asynchronous replies in C++

概览: 我有一个客户端-服务器实现,它使用 DBus(sdbus-c++) 向服务器发送异步请求。现在我的服务器与同步运行的硬件 API 交互,并且还需要大量时间来生成回复。所以我在服务器上有一个 std::queue ,它保存所有收到的异步请求,并一一处理它们。服务器处理后,以为发送的请求注册的回调的形式发回回复。

#client.h

class Client
{ 
    Client();
    ~Client();

    void sendRequestA() 
    {  
       ... use DBus async call to send request to server
    }

    void sendRequestB() {...}
    
    protected:
    virtual void replyCallbackA(const uint8_t& status) = 0 ; // ... callback invoked by the DBus server   
    virtual void replyCallbackB(const uint8_t& status) = 0 ;
}

Ì 在使用 std::async 测试此特定用例时遇到问题。

#test.cpp


//std::future<void> gFuture;

class ClientTest : public Client
{
  ClientTest();
  ~ClientTest();
  
  std::future<void> m_future;

  virtual void replyCallbackA(const uint8_t& status) override
  {
      std::cout<<"replyCallbackA status = "<< status<< "\n";
      m_future.get();
      //gFuture.get();
  }

  virtual void replyCallbackB(const uint8_t& status) override
  {
      std::cout<<"replyCallbackB status = "<< status<< "\n";
      m_future.get();
      //gFuture.get();

  }

}

int main()
{
   ClientTest cTest;
   cTest.m_future = std::async(std::launch::async, &ClientTest::sendRequestA, &cTest);
   cTest.m_future = std::async(std::launch::async, &ClientTest::sendRequestB, &cTest);

   //gFuture = = std::async(std::launch::async, &ClientTest::sendRequestA, &cTest);  -- no change in behavior with use of a global std::future.
}

我的理解是 sendRequestA & sendRequestB 会被调用,回调函数也会被调用。
但是,在这种情况下,main在调用sendRequestA & sendRequestB后立即退出,并且没有收到回调响应。

编辑:我也尝试过为 std::future 使用全局变量,但行为是一样的。

谁能告诉我我的理解错在哪里?

std::async returns 一个以传递给 std::async 的函数的 return 值完成的未来。

对 future 的第二次赋值将阻塞,直到对 sendRequestA 的调用完成(它阻塞是因为前一个 std::future 实例的析构函数)。它不会等到收到回复回调(除非你在 sendRequestA 中阻塞,但那会很奇怪)。

m_future.get() 在您的回复回调中将阻塞,直到未来得到解决(sendRequestA returns)。但是,它已经发送(因为这是您获得回复的唯一方式),因此 .get() 调用会立即 return。

我想你想使用更像 std::promise 的东西。在您的回复回调中,您将调用 std::promise::set_value 来解决未来的问题。对与 std::promisestd::future::get 关联的未来析构函数的调用将阻塞,直到 std::promise::set_value 被调用(或承诺被销毁)。