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
inmain()
- 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);
}