如何将sdbus-cpp与GLib事件循环(GMainLoop)集成?
实现sdbus-cpp与GMainLoop集成的思路及代码
先搞懂PollData里的两个文件描述符
fd:DBus连接的核心通信描述符,负责收发DBus消息,需要监听可读和可写事件(当sdbus-cpp有消息待发送时会标记该fd为可写)eventFd:sdbus-cpp用来唤醒事件循环的通知描述符,当有异步任务待处理时,sdbus-cpp会往这个fd写入数据,只需监听可读事件
核心实现步骤
- 从sdbus-cpp的
IConnection实例获取PollData结构 - 为两个fd分别创建
GSource,绑定到当前的GMainContext - 当fd触发对应事件时,调用sdbus-cpp的
processPendingRequests()处理所有待办任务 - 处理eventFd时必须读取内部数据,否则会重复触发可读事件
- 断开连接时销毁并释放
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
相关产品推荐
相关产品推荐

