You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将sdbus-cpp与GLib事件循环(GMainLoop)集成?

实现sdbus-cpp与GMainLoop集成的思路及代码

先搞懂PollData里的两个文件描述符

  • fd:DBus连接的核心通信描述符,负责收发DBus消息,需要监听可读和可写事件(当sdbus-cpp有消息待发送时会标记该fd为可写)
  • eventFd:sdbus-cpp用来唤醒事件循环的通知描述符,当有异步任务待处理时,sdbus-cpp会往这个fd写入数据,只需监听可读事件

核心实现步骤

  1. 从sdbus-cpp的IConnection实例获取PollData结构
  2. 为两个fd分别创建GSource,绑定到当前的GMainContext
  3. 当fd触发对应事件时,调用sdbus-cpp的processPendingRequests()处理所有待办任务
  4. 处理eventFd时必须读取内部数据,否则会重复触发可读事件
  5. 断开连接时销毁并释放GSource,避免资源泄漏

可运行的代码示例

#include <sdbus-c++/sdbus-c++.h>
#include <glib.h>
#include <unistd.h>

class SdbusGMainLoopBridge {
public:
    SdbusGMainLoopBridge(sdbus::IConnection& connection)
        : m_conn(connection)
    {
        auto pollData = m_conn.getEventLoopPollData();
        
        // 初始化DBus通信fd的事件源
        m_dbusSrc = g_unix_fd_source_new(pollData.fd, G_IO_IN | G_IO_OUT);
        g_source_set_callback(m_dbusSrc, &dbusFdHandler, this, nullptr);
        g_source_attach(m_dbusSrc, g_main_context_default());
        
        // 初始化eventFd的事件源
        m_eventSrc = g_unix_fd_source_new(pollData.eventFd, G_IO_IN);
        g_source_set_callback(m_eventSrc, &eventFdHandler, this, nullptr);
        g_source_attach(m_eventSrc, g_main_context_default());
    }

    ~SdbusGMainLoopBridge() {
        if (m_dbusSrc) {
            g_source_destroy(m_dbusSrc);
            g_source_unref(m_dbusSrc);
        }
        if (m_eventSrc) {
            g_source_destroy(m_eventSrc);
            g_source_unref(m_eventSrc);
        }
    }

private:
    static gboolean dbusFdHandler(GIOChannel*, GIOCondition cond, gpointer data) {
        auto self = static_cast<SdbusGMainLoopBridge*>(data);
        
        if (cond & (G_IO_IN | G_IO_OUT)) {
            self->m_conn.processPendingRequests();
        }
        
        // 返回TRUE保持事件源活跃
        return G_SOURCE_CONTINUE;
    }

    static gboolean eventFdHandler(GIOChannel*, GIOCondition cond, gpointer data) {
        auto self = static_cast<SdbusGMainLoopBridge*>(data);
        
        if (cond & G_IO_IN) {
            // 读取eventFd数据,消除触发标记
            uint64_t dummy;
            read(self->m_conn.getEventLoopPollData().eventFd, &dummy, sizeof(dummy));
            self->m_conn.processPendingRequests();
        }
        
        return G_SOURCE_CONTINUE;
    }

    sdbus::IConnection& m_conn;
    GSource* m_dbusSrc = nullptr;
    GSource* m_eventSrc = nullptr;
};

// 使用示例
int main() {
    // 创建系统DBus连接(也可改用session bus)
    auto dbusConn = sdbus::createSystemBusConnection();
    // 绑定sdbus-cpp到GMainLoop
    SdbusGMainLoopBridge bridge(*dbusConn);
    
    // 启动GLib主循环
    auto mainLoop = g_main_loop_new(nullptr, FALSE);
    g_main_loop_run(mainLoop);
    
    g_main_loop_unref(mainLoop);
    return 0;
}

关键注意事项

  • eventFd采用水平触发模式,必须读取内部数据才能清除事件标记,否则会持续触发可读事件
  • processPendingRequests()会统一处理所有DBus待办操作,包括消息接收、回复发送、异步调用回调等,无需区分触发源是fd还是eventFd
  • 如果应用使用自定义GMainContext,需将GSource绑定到对应上下文,而非默认的g_main_context_default()

内容的提问来源于stack exchange,提问作者mardy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 17:22:03