基于 C 中的“退出”标志正确终止 GLib 主循环

Ole*_*olf 3 c glib

我意识到这可能是一个新手 GLib 问题,但我很难在下面找到解决我的问题的代码示例。所以在我走错路之前,我希望得到你的建议。

我的代码侦听 D-Bus 消息。一条 D-Bus 消息是一条“退出”消息,旨在指示主循环关闭。如果主循环中没有其他任务,一个简单的解决方案可能是简单地调用g_main_loop_run()下面的代码,并在g_main_loop_quit()收到“退出”消息时执行 D-Bus 消息处理代码(此处未显示)。

但是,我更喜欢由主循环做出退出的决定,除了侦听 D-Bus 消息之外,它又可以执行各种其他任务。设置工作 D-Bus 服务器后,以下代码按预期执行此操作:

GMainLoop *glib_mainloop = g_main_loop_new( NULL, false );
/* Set up the D-Bus connection to work in the GLib event loop. */
dbus_connection_setup_with_g_main( dbus_connection, NULL );

/* Run the GLib event loop. */
GMainContext *glib_context = g_main_context_default( );
while( quit_indicator == false )
{
    g_main_context_iteration( glib_context, /*allow blocking=*/false );
    /* Do a variety of other tasks. */
}

g_main_loop_quit( glib_mainloop );
Run Code Online (Sandbox Code Playgroud)

注意:以上是用于说明我的问题的最少代码,我知道主循环中的“其他任务”可能更好地由线程、GSources 或其他方式处理。例如,如果按原样使用上述代码,则会出现明显的忙等待或计时问题。

我的问题是:上面的代码示例是完成我想要的正确方法还是有更“真实”的 GLib 方法?

Phi*_*all 6

你的方法基本上是正确的。许多示例都说要使用g_main_loop_run()g_main_loop_quit()控制主上下文,但在您执行操作时手动迭代主上下文会更清晰。

应该对您的代码进行的一项更改是g_main_context_iteration()允许阻塞,否则您的主循环本质上是一个繁忙的循环,并且您的进程在等待 I/O 时不会休眠。GMainLoop如果您GMainContext手动迭代,您也根本不需要使用 a 。

另一个必要的更改是g_main_context_wakeup()g_main_context_iteration()更改终止条件的值时调用从阻塞中唤醒主上下文。

第三,GMainLoop使用g_main_loop_new()/创建和退出g_main_loop_quit()在您的代码中没有任何作用,因为它GMainLoop永远不会与g_main_loop_run(). 挂断那些电话。

这是一个更新的版本:

GMainContext *context = g_main_context_default ();
gboolean quit = FALSE;

/* Set up the D-Bus connection to work in the GLib event loop. */
dbus_connection_setup_with_g_main (dbus_connection, context);

/* Run the GLib event loop. */
while (!quit)
  g_main_context_iteration (context, TRUE);

/* To exit the main loop (from a callback implementing your D-Bus Quit() function): */
quit = TRUE;
g_main_context_wakeup (NULL  /* global default main context */);
Run Code Online (Sandbox Code Playgroud)

其他几点:

  • 正如您所指出的,您评论中的“其他任务”应该在主上下文的回调中执行。
  • 使用 GDBus 而不是 dbus-glib(已弃用且未维护)。我在这里了一个关于为什么以及如何选择 D-Bus 绑定的答案
  • 如果您打算在新线程(而不是主线程)中执行此操作,则应使用GMainContext带有g_autoptr(GMainContext) context = g_main_context_new (); g_main_context_push_thread_default (context);. 您不应该GMainContext在多个线程之间共享 a 。虽然这样做是安全的,但它没有性能。

这是使用这些技术的现代基于 GLib 的守护程序中主循环的 MPL 许可示例:https : //git.apertis.org/cgit/rhosydd.git/tree/libcroesor/service.c#n569