`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::promise
或 std::future::get
关联的未来析构函数的调用将阻塞,直到 std::promise::set_value
被调用(或承诺被销毁)。
概览:
我有一个客户端-服务器实现,它使用 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::promise
或 std::future::get
关联的未来析构函数的调用将阻塞,直到 std::promise::set_value
被调用(或承诺被销毁)。