]> Pileus Git - ~andy/gtk/blobdiff - docs/reference/gdk/tmpl/threads.sgml
Make 3.0 parallel-installable to 2.x
[~andy/gtk] / docs / reference / gdk / tmpl / threads.sgml
index 5e7e049abbf686fbadd74c98d84bc193ac009c4b..75a61ee8407f46b00053e07223ae8a0a2bf7bcaa 100644 (file)
 Threads
 
 <!-- ##### SECTION Short_Description ##### -->
-
+Functions for using GDK in multi-threaded programs
 
 <!-- ##### SECTION Long_Description ##### -->
 <para>
+For thread safety, GDK relies on the thread primitives in GLib, 
+and on the thread-safe GLib main loop.
+</para>
+<para>
+GLib is completely thread safe (all global data is automatically 
+locked), but individual data structure instances are not automatically 
+locked for performance reasons. So e.g. you must coordinate 
+accesses to the same #GHashTable from multiple threads.
+</para>
+<para>
+GTK+ is "thread aware" but not thread safe &mdash; it provides a
+global lock controlled by gdk_threads_enter()/gdk_threads_leave()
+which protects all use of GTK+. That is, only one thread can use GTK+ 
+at any given time.
+</para>
+<para>
+Unfortunately the above holds with the X11 backend only. With the
+Win32 backend, GDK calls should not be attempted from multiple threads
+at all.
+</para>
+<para>
+You must call g_thread_init() and gdk_threads_init() before executing
+any other GTK+ or GDK functions in a threaded GTK+ program.
+</para>
+<para>
+Idles, timeouts, and input functions from GLib, such as g_idle_add(), are
+executed outside of the main GTK+ lock.
+So, if you need to call GTK+ inside of such a callback, you must surround
+the callback with a gdk_threads_enter()/gdk_threads_leave() pair or use
+gdk_threads_add_idle_full() which does this for you.
+However, event dispatching from the mainloop is still executed within
+the main GTK+ lock, so callback functions connected to event signals
+like GtkWidget::button-press-event, do not need thread protection.
+</para>
+<para>
+In particular, this means, if you are writing widgets that might 
+be used in threaded programs, you <emphasis>must</emphasis> surround 
+timeouts and idle functions in this matter.
+</para>
+<para>
+As always, you must also surround any calls to GTK+ not made within 
+a signal handler with a gdk_threads_enter()/gdk_threads_leave() pair.
+</para>
+
+<para>
+Before calling gdk_threads_leave() from a thread other
+than your main thread, you probably want to call gdk_flush()
+to send all pending commands to the windowing system.
+(The reason you don't need to do this from the main thread
+is that GDK always automatically flushes pending commands
+when it runs out of incoming events to process and has
+to sleep while waiting for more events.)
+</para>
+
+<para>A minimal main program for a threaded GTK+ application
+looks like:</para>
+
+<informalexample>
+<programlisting role="C">
+int
+main (int argc, char *argv[])
+{
+  GtkWidget *window;
 
+  g_thread_init (NULL);
+  gdk_threads_init (<!-- -->);
+  gdk_threads_enter (<!-- -->);
+
+  gtk_init (&amp;argc, &amp;argv);
+
+  window = create_window (<!-- -->);
+  gtk_widget_show (window);
+
+  gtk_main (<!-- -->);
+  gdk_threads_leave (<!-- -->);
+
+  return 0;
+}
+</programlisting>
+</informalexample>
+
+<para>
+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.
 </para>
 
+<para>Erik Mouw contributed the following code example to
+illustrate how to use threads within GTK+ programs.
+</para>
+
+<informalexample>
+<programlisting role="C">
+/*-------------------------------------------------------------------------
+ * Filename:      gtk-thread.c
+ * Version:       0.99.1
+ * Copyright:     Copyright (C) 1999, Erik Mouw
+ * Author:        Erik Mouw &lt;J.A.K.Mouw@its.tudelft.nl&gt;
+ * Description:   GTK threads example. 
+ * Created at:    Sun Oct 17 21:27:09 1999
+ * Modified by:   Erik Mouw &lt;J.A.K.Mouw@its.tudelft.nl&gt;
+ * Modified at:   Sun Oct 24 17:21:41 1999
+ *-----------------------------------------------------------------------*/
+/*
+ * Compile with:
+ *
+ * cc -o gtk-thread gtk-thread.c `gtk-config --cflags --libs gthread`
+ *
+ * Thanks to Sebastian Wilhelmi and Owen Taylor for pointing out some
+ * bugs.
+ *
+ */
+
+&num;include &lt;stdio.h&gt;
+&num;include &lt;stdlib.h&gt;
+&num;include &lt;unistd.h&gt;
+&num;include &lt;time.h&gt;
+&num;include &lt;gtk/gtk.h&gt;
+&num;include &lt;glib.h&gt;
+&num;include &lt;pthread.h&gt;
+
+&num;define YES_IT_IS    (1)
+&num;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(rand(<!-- -->) / (RAND_MAX / 3) + 1);
+
+      /* 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!");
+
+         /* release GTK thread lock */
+         gdk_threads_leave (<!-- -->);
+       }
+    }
+
+  return NULL;
+}
+
+int main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *label;
+  yes_or_no_args yes_args, no_args;
+  pthread_t no_tid, yes_tid;
+
+  /* init threads */
+  g_thread_init (NULL);
+  gdk_threads_init (<!-- -->);
+  gdk_threads_enter (<!-- -->);
+
+  /* init gtk */
+  gtk_init(&amp;argc, &amp;argv);
+
+  /* init random number generator */
+  srand ((unsigned int) time (NULL));
+
+  /* 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;
+  pthread_create (&amp;yes_tid, NULL, argument_thread, &amp;yes_args);
+
+  no_args.label = label;
+  no_args.what = NO_IT_IS_NOT;
+  pthread_create (&amp;no_tid, NULL, argument_thread, &amp;no_args);
+
+  /* enter the GTK main loop */
+  gtk_main (<!-- -->);
+  gdk_threads_leave (<!-- -->);
+
+  return 0;
+}
+</programlisting>
+</informalexample>
+
 <!-- ##### SECTION See_Also ##### -->
 <para>
 
 </para>
 
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### SECTION Image ##### -->
+
+
 <!-- ##### MACRO GDK_THREADS_ENTER ##### -->
 <para>
-
+This macro marks the beginning of a critical section in which GDK and
+GTK+ functions can be called safely and without causing race
+conditions.  Only one thread at a time can be in such a critial
+section. The macro expands to a no-op if #G_THREADS_ENABLED has not
+been defined. Typically gdk_threads_enter() should be used instead of
+this macro.
 </para>
 
 
 
 <!-- ##### MACRO GDK_THREADS_LEAVE ##### -->
 <para>
+This macro marks the end of a critical section 
+begun with #GDK_THREADS_ENTER.
+</para>
+
+
+
+<!-- ##### FUNCTION gdk_threads_init ##### -->
+<para>
 
 </para>
 
+@void: 
 
 
 <!-- ##### FUNCTION gdk_threads_enter ##### -->
 <para>
-
+This macro marks the beginning of a critical section in which GDK and
+GTK+ functions can be called safely and without causing race
+conditions.  Only one thread at a time can be in such a critial
+section.
 </para>
 
+@void: 
 
 
 <!-- ##### FUNCTION gdk_threads_leave ##### -->
 <para>
-
+Leaves a critical region begun with gdk_threads_enter(). 
 </para>
 
+@void: 
 
 
 <!-- ##### VARIABLE gdk_threads_mutex ##### -->
 <para>
+The #GMutex used to implement the critical region for
+gdk_threads_enter()/gdk_threads_leave(). 
+</para>
+
+
+<!-- ##### FUNCTION gdk_threads_set_lock_functions ##### -->
+<para>
+
+</para>
+
+@enter_fn: 
+@leave_fn: 
+
+
+<!-- ##### FUNCTION gdk_threads_add_idle ##### -->
+<para>
 
 </para>
 
+@function: 
+@data: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gdk_threads_add_idle_full ##### -->
+<para>
+
+</para>
+
+@priority: 
+@function: 
+@data: 
+@notify: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gdk_threads_add_timeout ##### -->
+<para>
+
+</para>
+
+@interval: 
+@function: 
+@data: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gdk_threads_add_timeout_full ##### -->
+<para>
+
+</para>
+
+@priority: 
+@interval: 
+@function: 
+@data: 
+@notify: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gdk_threads_add_timeout_seconds ##### -->
+<para>
+
+</para>
+
+@interval: 
+@function: 
+@data: 
+@Returns: 
+
+
+<!-- ##### FUNCTION gdk_threads_add_timeout_seconds_full ##### -->
+<para>
+
+</para>
+
+@priority: 
+@interval: 
+@function: 
+@data: 
+@notify: 
+@Returns: 
+