g_timeout_add inside a GThread

2019-05-28 12:47发布

问题:

I'm trying to add a timeout source specific to a particular GThread.

In the main thread, I can create a GMainContext (g_main_context_new) and add a timeout (g_timeout_add). However, when I try to do it in a thread created with g_thread_create it simply doesn't work, the GSourceFunc is never called and I have no clue why.

For the moment I've only got this the documentation:

Callbacks require a bit of attention. Callbacks from GTK+ (signals) are made within the GTK+ lock. However callbacks from GLib (timeouts, IO callbacks, and idle functions) are made outside of the GTK+ lock. So, within a signal handler you do not need to call gdk_threads_enter(), but within the other types of callbacks, you do.

But my timeout function (for testing purposes) only prints in the console, so I don't think it's a problem of resource protection and mutexes.

The thread structure is:

Main thread --> no GLib main context explicitly created

  • capture thread

  • process thread --> should have a GLib main context and a timeout source

  • show thread

I appreciate any help.

Thanks in advance.

回答1:

Do you use g_timeout_add() or g_source_attach()?

g_timeout_add() and g_timeout_add_full() does not allow you to specify which main context to add. It always use the default main context. if you are not using the default main context in your main thread, it is perfectly ok to use it in your process thread. You can read about it in the description.

A GMainContext can only be running in a single thread

The default main context is implicitly created by many functions, including g_main_context_default(). So please make sure that you have not using it in your main thread.

You can use g_source_attach() to add a timeout source to your own main context if you decided to do so. There is no timeout function you can use to specify your main context. So, just do it by your self.

The following code is basically same as: g_timeout_add_full(G_PRIORITY_DEFAULT, 100, func, l, notify);

#include <glib.h>

void notify(gpointer data)
{
        g_main_loop_quit((GMainLoop *)data);
}

gboolean func(gpointer data)
{
        static gint i = 0;
        g_message("%d", i++);
        return (i < 10) ? TRUE : FALSE;
}

gpointer thread(gpointer data)
{
        GMainContext *c;
        GMainContext *d;
        GMainLoop *l;
        GSource *s;

        c = g_main_context_new();
        d = g_main_context_default();

        g_message("local: %p", c);
        g_message("default: %p", d);

#if 1
        l = g_main_loop_new(c, FALSE);
        s = g_timeout_source_new(100);
        g_source_set_callback(s, func, l, notify);
        g_source_attach(s, c);
        g_source_unref(s);
#else
        l = g_main_loop_new(d, FALSE);
        g_timeout_add_full(G_PRIORITY_DEFAULT, 100, func, l, notify);
#endif

        g_main_loop_run(l);
        g_message("done");

        return NULL;
}

int main(int argc, char *argv[])
{
        GError *error = NULL;
        GThread *t;

        g_thread_init(NULL);
        t = g_thread_create(thread, NULL, TRUE, &error);
        g_thread_join(t);

        return 0;
}