<!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
>