同时运行多个GMainLoops

20
用户可以在多个线程中同时运行多个GMainLoop实例,每个线程运行自己的实例吗?我发现这个问题的答案有“是”和“否”。我意识到这个问题在这个论坛上已经被问过(2011年12月)
然而,我能够同时运行两个GMainLoop实例,没有明显的问题。我的测试代码非常简单:
  1. main() 中创建一个 GMainLoop
  2. 使用 g_timeout_add 为默认上下文和主循环创建超时源
  3. 在 main() 中创建一个 GThread
  4. 使用 g_main_loop_run 运行主循环
  5. [THREAD CONTEXT]: 使用 g_main_context_new 创建一个上下文
  6. [THREAD CONTEXT]: 使用 g_main_context_push_thread_default 将该上下文设置为线程默认值
  7. [THREAD CONTEXT]: 使用 g_main_loop_new 创建一个循环,并将其赋予新的上下文
  8. [THREAD CONTEXT]: 创建一个超时源,并通过 g_source_attach 将其附加到新的上下文中
  9. [THREAD_CONTEXT]: 让线程调用 g_main_loop_run

这样做,我看到两个实例的 GMainLoop 都能正常工作。超时回调被正确地调用,后续对 g_main_loop_quit 的调用也能按预期运行。

看起来同时拥有多个GMainLoop实例并不是一个问题。但是也许我还没有充分了解API,对这种情况没有一个明确的答案吗?

另外,如果有人感兴趣,这里是实际测试代码:

#define THREAD_TIMEOUTS (20)
#define MAIN_TIMEOUS (1)

typedef struct timeout_struct
{
    int i;
    int max;
    GMainLoop *loop;
    char *name;

} TIMEOUT_STRUCT;

gboolean timeout_callback(gpointer data)
{
    TIMEOUT_STRUCT *psTimeout = (TIMEOUT_STRUCT *)data;

    psTimeout->i++;

    if (psTimeout->i == psTimeout->max)
    {
        if (psTimeout->max == THREAD_TIMEOUTS)
        {
            g_main_loop_quit( (GMainLoop*)psTimeout->loop );
        }
        return FALSE;
    }

    return TRUE;
}
void* thread_function(void *data)
{
    GMainContext *ps_context;
    GMainLoop *ps_loop;
    GSource *ps_timer;
    TIMEOUT_STRUCT sTimeout;

    ps_context = g_main_context_new();
    g_main_context_push_thread_default(ps_context);

    ps_loop = g_main_loop_new(ps_context, FALSE);

    sTimeout.i = 0;
    sTimeout.max = THREAD_TIMEOUTS;
    sTimeout.loop = ps_loop;
    sTimeout.name = "thread";
    ps_timer = g_timeout_source_new_seconds(1);
    g_source_set_callback(ps_timer, timeout_callback, &sTimeout, NULL);
    g_source_attach(ps_timer, ps_context);

    g_main_loop_run(ps_loop);

    g_main_loop_quit( (GMainLoop*)data );

    return NULL;

}
/*
 * This main boots a thread, then starts up a GMainLoop.  Then the thread runs
 * a GMainLoop.  The thread sets a timer that fires ten times and the main sets a
 * timer that fires two times. The thread quits and
 * and then the other main l
 *
 *
 * */
int main()
{
    GThread *ps_thread;
    GMainLoop *loop;
    TIMEOUT_STRUCT sTimeout;

    loop = g_main_loop_new ( NULL , FALSE );

    sTimeout.i = 0;
    sTimeout.max = MAIN_TIMEOUS;
    sTimeout.loop = loop;
    sTimeout.name = "main";

    // add source to default context
    g_timeout_add (1 , timeout_callback, &sTimeout);

    ps_thread = g_thread_new("thread", thread_function, loop);

    g_main_loop_run (loop);
    g_main_loop_unref(loop);
}

我刚刚发现了这个,它似乎认为这是GLib API的可接受用法。所以,我想这是“没问题”的一列中的另一个条目吧。 - pkurby
1个回答

20

《GTK+开发基础》一书指出:

GLib主循环由多个结构实现,这些结构允许多个实例并行运行。

因此,根据这个,我的测试代码和我在上面评论中发布的链接,我们对这个问题有一个明确的答案。

也就是说:多个线程可以拥有自己的GMainContext和GMainLoop,并能够以并发的方式独立运行这些循环。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接