我正在与 libportal 合作来自 C++ 的库改进 Flatpak支持现有的应用程序,并且我遇到了 libportal 公开的许多 API 都是异步的问题,但我正在使用的代码库是以假设相关操作是同步的方式编写的。当然,我可以重构代码以支持异步操作,但这需要对应用程序的代码库进行重大更改,并且就我需要 libportal 的目的而言,这不会带来明显的好处,主线程被阻塞并不重要。我曾与一位 libportal 维护者交谈过,他说他对添加我想要使用的 API 的同步变体( xdp_portal_open_file
)不感兴趣,而是建议我自己制作一个同步包装器,这最终让我意识到我的问题:
如何在 C++ 中为基于回调的异步函数创建同步包装器?在本例中,回调是 GAsyncReadyCallback
来自Gio 2.0 .
最佳答案
我使用条件变量为您创建了一个示例。 我没有你的框架,所以我使用 std::async 来模拟异步调用。
该示例的基本内容是启动异步调用,让回调在异步函数完成时设置一个信号。然后,调用线程将阻塞,直到设置标志为止(同时不花费任何 CPU 时间)。
#include <chrono>
#include <future>
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
// use a condition variable, a mutex and a flag to build a synchronization point.
// condition variables are more like a signal between threads then a real variable!
// and are used a lot to do inter-thread signaling, because the avoid busy loops
class synchronization_point_t
{
public:
void set()
{
std::unique_lock<std::mutex> lock{ m_mtx };
m_flag = true;
m_cv.notify_all();
}
void wait()
{
std::unique_lock<std::mutex> lock{ m_mtx };
m_cv.wait(lock, [&] {return m_flag; });
}
private:
std::mutex m_mtx;
std::condition_variable m_cv;
bool m_flag{ false };
};
//-----------------------------------------------------------------------------
void callback(void* userdata)
{
std::cout << "callback setting synchronization point signal\n";
auto synchronization_point = reinterpret_cast<synchronization_point_t*>(userdata);
synchronization_point->set();
}
void async_fn(void* userdata)
{
std::cout << "async_fn starting\n";
// simulate some work here
for (std::size_t n = 0; n < 10; ++n)
{
std::cout << ".";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
std::cout << "\n";
std::cout << "async_fn calling callback\n";
callback(userdata);
std::cout << "async_fn done\n";
}
void fn()
{
std::cout << "fn() creating a synchronization point\n";
synchronization_point_t synchronization_point;
std::cout << "fn() calling the asynchronous variant\n";
auto future = std::async(std::launch::async, [&]
{
async_fn(reinterpret_cast<void*>(&synchronization_point));
});
// this will wait until the function has called the callbacks
std::cout << "fn() waiting for the asynchronous call to complete\n";
synchronization_point.wait();
std::cout << "fn() done\n";
}
int main()
{
std::cout << "main calling synchronous version of fn()\n";
fn();
std::cout << "main done\n";
return 0;
}
关于c++ - 如何在 C++ 中围绕异步回调创建同步包装器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70785862/