c++asynchronousdbusstdasync

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


Overview : I have a client-server implementation, which uses DBus(sdbus-c++) to send asynchronous requests to a server. Now my server interacts with hardware APIs which behaves synchronously and also takes significant time to generate a reply. So I have a std::queue at server, that holds all the asynchronous requests received, and processes them one by one. After processing the server, sends the reply back in the form of callback that was registered for the request sent.

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

Ì am facing issues with using std::async to test this particular usecase.

#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.
}

My understanding here was that the sendRequestA & sendRequestB, would be called and as well the callback functions will be invoked.
However, in this case, the main exits immediately after calling the sendRequestA & sendRequestB and the callback response is not received.

Edit: I have also tried using a global variable for std::future, but the behavior was the same.

Could anyone tell where my understanding is at fault?


Solution

  • std::async returns a future that completes with the return value of the function passed to std::async.

    The second assignment to the future will block until the call to sendRequestA completes (it blocks because of the destructor of the previous std::future instance). It does not wait until the reply callback is received (unless you are blocking in sendRequestA but that would be strange).

    m_future.get() in your reply callbacks will block until the future is resolved (sendRequestA returns). However, it will have been sent already (because that is the only way you would get a reply) and so the .get() call would return immediately.

    I think you want to be using something more like std::promise. In your reply callback you would call std::promise::set_value to resolve the future. Calls to the destructor of the future associated with the std::promise or to std::future::get will block until std::promise::set_value is called (or the promise is destroyed).