<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd"> <HTML ><HEAD ><TITLE >Is GTK+ thread safe? How do I write multi-threaded GTK+ applications? [GTK 2.x]</TITLE ><META NAME="GENERATOR" CONTENT="Modular DocBook HTML Stylesheet Version 1.79"><LINK REL="HOME" TITLE="GTK+ FAQ" HREF="book1.html"><LINK REL="UP" TITLE="Development with GTK+: general questions" HREF="c466.html"><LINK REL="PREVIOUS" TITLE="Development with GTK+: general questions" HREF="c466.html"><LINK REL="NEXT" TITLE="I'm doing some stuff with GTK+ in a separate thread, and properly locking with gdk_threads_enter/gdk_threads_leave() but the display doesn't update properly. [GTK 2.x]" HREF="x482.html"></HEAD ><BODY CLASS="SECT1" BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#840084" ALINK="#0000FF" ><DIV CLASS="NAVHEADER" ><TABLE SUMMARY="Header navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TH COLSPAN="3" ALIGN="center" >GTK+ FAQ</TH ></TR ><TR ><TD WIDTH="10%" ALIGN="left" VALIGN="bottom" ><A HREF="c466.html" ACCESSKEY="P" ><<< Previous</A ></TD ><TD WIDTH="80%" ALIGN="center" VALIGN="bottom" >Development with GTK+: general questions</TD ><TD WIDTH="10%" ALIGN="right" VALIGN="bottom" ><A HREF="x482.html" ACCESSKEY="N" >Next >>></A ></TD ></TR ></TABLE ><HR ALIGN="LEFT" WIDTH="100%"></DIV ><DIV CLASS="SECT1" ><H1 CLASS="SECT1" ><A NAME="AEN472" >Is GTK+ thread safe? How do I write multi-threaded GTK+ applications? <I CLASS="EMPHASIS" >[GTK 2.x]</I ></A ></H1 ><P >The GLib library can be used in a thread-safe mode by calling g_thread_init() before making any other GLib calls. In this mode GLib automatically locks all internal data structures as needed. This does not mean that two threads can simultaneously access, for example, a single hash table, but they can access two different hash tables simultaneously. If two different threads need to access the same hash table, the application is responsible for locking itself.</P ><P >In order to make GDK thread aware, you also need to call gdk_threads_init() in conjunction with the above call. There is a single global lock that you must acquire with gdk_threads_enter() before making any GDK calls, and release with gdk_threads_leave() afterwards throughout your code.</P ><P >A minimal main program for a threaded GTK+ application looks like:</P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><PRE CLASS="PROGRAMLISTING" >int main (int argc, char *argv[]) { GtkWidget *window; /* init threads */ g_thread_init(NULL); gdk_threads_init(); /* init gtk */ gtk_init(&argc, &argv); window = create_window(); gtk_widget_show(window); gdk_threads_enter(); gtk_main(); gdk_threads_leave(); return 0; }</PRE ></TD ></TR ></TABLE ><P >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.</P ><P >Erik Mouw contributed the following code example to illustrate how to use threads within GTK+ programs.</P ><TABLE BORDER="0" BGCOLOR="#E0E0E0" WIDTH="100%" ><TR ><TD ><PRE CLASS="PROGRAMLISTING" >/*------------------------------------------------------------------------- * Filename: gtk-thread.c * Version: 1.99.1 * Copyright: Copyright (C) 1999, Erik Mouw * Author: Erik Mouw <J.A.K.Mouw@its.tudelft.nl> * Description: GTK threads example. * Created at: Sun Oct 17 21:27:09 1999 * Modified by: Owen Taylor <otaylor@gtk.org> * Modified at: Wed May 28 10:43:00 2003 *-----------------------------------------------------------------------*/ /* * Compile with: * * cc -o gtk-thread gtk-thread.c `pkg-config --cflags --libs gtk+-2.0 gthread-2.0` * * Thanks to Sebastian Wilhelmi for pointing out some bugs in earlier versions. * */ #include <unistd.h> #include <gtk/gtk.h> #define YES_IT_IS (1) #define NO_IT_IS_NOT (0) typedef struct { GtkWidget *label; int what; } yes_or_no_args; G_LOCK_DEFINE_STATIC (yes_or_no); static volatile int yes_or_no = YES_IT_IS; void destroy(GtkWidget *widget, gpointer data) { gtk_main_quit(); } void *argument_thread(void *args) { yes_or_no_args *data = (yes_or_no_args *)args; gboolean say_something; for(;;) { /* sleep a while */ sleep(g_random_int_range (1, 4)); /* lock the yes_or_no_variable */ G_LOCK(yes_or_no); /* do we have to say something? */ say_something = (yes_or_no != data->what); if(say_something) { /* set the variable */ yes_or_no = data->what; } /* Unlock the yes_or_no variable */ G_UNLOCK(yes_or_no); if(say_something) { /* get GTK thread lock */ gdk_threads_enter(); /* set label text */ if(data->what == YES_IT_IS) gtk_label_set_text(GTK_LABEL(data->label), "O yes, it is!"); else gtk_label_set_text(GTK_LABEL(data->label), "O no, it isn't!"); /* Make sure all X commands are sent to the X server; not strictly * necessary here, but always a good idea when you do anything * from a thread other than the one where the main loop is running. */ gdk_flush (); /* release GTK thread lock */ gdk_threads_leave(); } } return NULL; } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *label; GError *error = NULL; yes_or_no_args yes_args, no_args; /* init threads */ g_thread_init(NULL); gdk_threads_init(); /* init gtk */ gtk_init(&argc, &argv); /* create a window */ window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(window, "destroy", G_CALLBACK(destroy), NULL); gtk_container_set_border_width(GTK_CONTAINER (window), 10); /* create a label */ label = gtk_label_new("And now for something completely different ..."); gtk_container_add(GTK_CONTAINER(window), label); /* show everything */ gtk_widget_show(label); gtk_widget_show (window); /* create the threads */ yes_args.label = label; yes_args.what = YES_IT_IS; if (!g_thread_create(argument_thread, &yes_args, FALSE, &error)) { g_printerr ("Failed to create YES thread: %s\n", error->message); return 1; } no_args.label = label; no_args.what = NO_IT_IS_NOT; if (!g_thread_create(argument_thread, &no_args, FALSE, &error)) { g_printerr ("Failed to create NO thread: %s\n", error->message); return 1; } /* enter the GTK main loop */ gdk_threads_enter(); gtk_main(); gdk_threads_leave(); return 0; }</PRE ></TD ></TR ></TABLE ></DIV ><DIV CLASS="NAVFOOTER" ><HR ALIGN="LEFT" WIDTH="100%"><TABLE SUMMARY="Footer navigation table" WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0" ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" ><A HREF="c466.html" ACCESSKEY="P" ><<< Previous</A ></TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" ><A HREF="book1.html" ACCESSKEY="H" >Home</A ></TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" ><A HREF="x482.html" ACCESSKEY="N" >Next >>></A ></TD ></TR ><TR ><TD WIDTH="33%" ALIGN="left" VALIGN="top" >Development with GTK+: general questions</TD ><TD WIDTH="34%" ALIGN="center" VALIGN="top" ><A HREF="c466.html" ACCESSKEY="U" >Up</A ></TD ><TD WIDTH="33%" ALIGN="right" VALIGN="top" >I'm doing some stuff with GTK+ in a separate thread, and properly locking with gdk_threads_enter/gdk_threads_leave() but the display doesn't update properly. <I CLASS="EMPHASIS" >[GTK 2.x]</I ></TD ></TR ></TABLE ></DIV ></BODY ></HTML >