According to the documentation, the main even loop can accept sources from different threads:
A GMainContext can only be running in a single thread, but sources can
be added to it and removed from it from other threads.
So you can inject the code in the UI thread from your working thread by:
- creating a
GSource
(e.g., by using g_idle_source_new
);
- adding the code you want to be executed with
g-source-set-callback
;
- attaching it to the UI thread context with
g_source_attach()
.
Here is a sample program for GTK+2 and GLib >= 2.32:
#include <gtk/gtk.h>
#define N_THREADS 100
#define N_ITERATIONS 100
GtkWidget *bar;
GMainContext *context;
static gboolean
update_progress_bar(gpointer user_data)
{
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(bar),
g_random_double_range(0, 1));
return G_SOURCE_REMOVE;
}
static gpointer
thread_func(gpointer user_data)
{
int n_thread = GPOINTER_TO_INT(user_data);
int n;
GSource *source;
g_print("Starting thread %d
", n_thread);
for (n = 0; n < N_ITERATIONS; ++n) {
/* If you want to see anything you should add a delay
* to let the main loop update the UI, e.g.:
* g_usleep(g_random_int_range(1234, 567890));
*/
source = g_idle_source_new();
g_source_set_callback(source, update_progress_bar, NULL, NULL);
g_source_attach(source, context);
g_source_unref(source);
}
g_print("Ending thread %d
", n_thread);
return NULL;
}
gint
main(gint argc, gchar *argv[])
{
GtkWidget *window;
GThread *thread[N_THREADS];
int n;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
bar = gtk_progress_bar_new();
gtk_container_add(GTK_CONTAINER(window), bar);
context = g_main_context_default();
for (n = 0; n < N_THREADS; ++n)
thread[n] = g_thread_new(NULL, thread_func, GINT_TO_POINTER(n));
gtk_widget_show_all(window);
gtk_main();
for (n = 0; n < N_THREADS; ++n)
g_thread_join(thread[n]);
return 0;
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…