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

时间:2018-01-08 11:37:46

标签: c glib

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

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

但是,我更喜欢由主循环决定退出,主循环除了监听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 );

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

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

1 个答案:

答案 0 :(得分:2)

您的方法基本上是正确的。很多例子都说使用g_main_loop_run()g_main_loop_quit()来控制主要的上下文,但是你可以手动迭代主上下文。

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

另一个必要的变化是,当您更改终止条件的值时,调用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 */);

其他几点:

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

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