c++ - 如何在 C++ 中围绕异步回调创建同步包装器?

标签 c++ asynchronous callback synchronization asynccallback

我正在与 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/

相关文章:

c++ - 如何将 Eigen::Matrix4f 转换为 Eigen::Affine3f

javascript - 如何在 Rails 中异步/使用 AJAX 呈现部分内容?

c# - 异步方法中的奇怪调试器行为

javascript - 如何在回调中访问正确的“this”?

c++ - 试图调用模板类的友元函数

c++ - SetupDiEnumDeviceInterfaces 失败问题

c++ - 为什么我有一个无限循环,我该如何做呢?

javascript - Vuejs 计算属性依赖于其他异步计算属性

node.js - 无法解构属性错误 - googleapi

jquery - 如何处理多个ajax请求?