Запуск нескольких параллельных GMainLoops

пользователям GLib разрешено запускать несколько GMainLoop экземпляры одновременно в нескольких потоках, причем каждый поток запускает свой собственный экземпляр? Я повсюду нахожу ответы "да" и "нет". Я понимаю, что этот вопрос задавался раньше на этом самом форуме (декабрь 2011 года).

тем не менее, я могу запустить два GMainLoop экземпляры в то же время без явной проблемы. Мой тестовый код очень простой:

  1. создать GMainLoop в main()
  2. создайте источник тайм-аута для контекста по умолчанию и основного цикла с помощью g_timeout_add
  3. создайте GThread в main ()
  4. запустите основной цикл с помощью g_main_loop_run
  5. [контекст потока]: создайте контекст с помощью g_main_context_new
  6. [контекст потока]: установите этот контекст как поток по умолчанию, используя g_main_context_push_thread_default
  7. [контекст потока]: создайте цикл, используя g_main_loop_new и дайте ему новый контекст
  8. [контекст потока]: создайте источник тайм-аута и присоедините его к новому контексту через g_source_attach.
  9. [THREAD_CONTEXT]: пусть поток вызовет g_main_loop_run

делая это, я вижу оба экземпляра GMainLoop работает просто отлично. Обратные вызовы timeout вызываются правильно, а последующие вызовы 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);
}

1 ответов


в книге "Основы развития GTK+" говорится следующее:

основной цикл GLib реализован в виде нескольких структур, которые позволяют использовать несколько экземпляров запускаться одновременно.

Итак, учитывая это, мой тестовый код и ссылке я опубликовал в комментарии выше, у нас есть окончательный ответ на этот вопрос.

а именно: несколько потоков могут иметь свой собственный GMainContext & GMainLoop и могут независимо работать эти петли одновременно.