Running multiple concurrent GMainLoops

c, glib, multithreading

Solution

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.

Problem

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: - Create a `GMainLoop` in `main()` - Create a timeout source for the default context and the main loop using `g_timeout_add` - Create a GThread in main() - Run the main loop using `g_main_loop_run` - [THREAD CONTEXT]: Create a context using `g_main_context_new` - [THREAD CONTEXT]: Set that context as the thread default using `g_main_context_push_thread_default` - [THREAD CONTEXT]: Create a loop using `g_main_loop_new` and give it the new context - [THREAD CONTEXT]: Create a timeout source, and attach it to the new context via `g_source_attach`. - [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); } ```

Original source

Related problems