Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running multiple concurrent GMainLoops

Are users of GLib allowed to run multiple GMainLoop instances concurrently in multiple threads, with each thread running its own instance? I've found "yes" and "no" answers all over the place. I realize that this question has been asked before in this very forum (December 2011).

However, I am able to run two GMainLoop instances at the same time without apparent issue. My test code is very simple:

  1. Create a GMainLoop in main()
  2. Create a timeout source for the default context and the main loop using g_timeout_add
  3. Create a GThread in main()
  4. Run the main loop using g_main_loop_run
  5. [THREAD CONTEXT]: Create a context using g_main_context_new
  6. [THREAD CONTEXT]: Set that context as the thread default using g_main_context_push_thread_default
  7. [THREAD CONTEXT]: Create a loop using g_main_loop_new and give it the new context
  8. [THREAD CONTEXT]: Create a timeout source, and attach it to the new context via g_source_attach.
  9. [THREAD_CONTEXT]: Have the thread invoke g_main_loop_run

Doing this, I see both instances of the GMainLoop working just fine. The timeout callbacks are invoked correctly, and later calls to g_main_loop_quit work as expected.

So, it looks like it is not a problem to have multiple GMainLoop instances working concurrently. But perhaps I just haven't exercised the API enough to fully grasp the situation. Is there a definitive answer to this question?

Also, here's the actual test code if anybody cares to look:

#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);
}
like image 278
pkurby Avatar asked Jan 31 '14 16:01

pkurby


1 Answers

The book "Foundations of GTK+ Development" states this:

The GLib main loop is implemented as a number of structures, which allow multiple instances to be run concurrently.

So, given this, my test code, and the link I posted in the comment above we have a definitive answer to this question.

Namely: Multiple threads may have their own GMainContext & GMainLoop, and are able to independently run these loops in a concurrent fashion.

like image 80
pkurby Avatar answered Oct 24 '22 04:10

pkurby