summaryrefslogtreecommitdiff
path: root/gdk/gdk.c
diff options
context:
space:
mode:
authorJavier Jardón <jjardon@gnome.org>2010-11-15 19:37:28 +0100
committerJavier Jardón <jjardon@gnome.org>2010-11-15 21:06:35 +0100
commitb63800bd33b8abbaad937a87c5e0d066765bcbb5 (patch)
treef1eb4757bcc1a86987a707472f331f0d756bbb66 /gdk/gdk.c
parent4400f997a8e1f40116a6754dbdf5a28619da90bf (diff)
downloadgtk+-b63800bd33b8abbaad937a87c5e0d066765bcbb5.tar.gz
docs: Move documentation to inline comments: gdkthreads
Diffstat (limited to 'gdk/gdk.c')
-rw-r--r--gdk/gdk.c245
1 files changed, 244 insertions, 1 deletions
diff --git a/gdk/gdk.c b/gdk/gdk.c
index 8c701ff6e6..f0ff4336eb 100644
--- a/gdk/gdk.c
+++ b/gdk/gdk.c
@@ -399,6 +399,244 @@ gdk_init (int *argc, char ***argv)
}
}
+
+
+/**
+ * SECTION:threads
+ * @Short_description: Functions for using GDK in multi-threaded programs
+ * @Title: Threads
+ *
+ * For thread safety, GDK relies on the thread primitives in GLib,
+ * and on the thread-safe GLib main loop.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * Unfortunately the above holds with the X11 backend only. With the
+ * Win32 backend, GDK calls should not be attempted from multiple threads
+ * at all.
+ *
+ * You must call g_thread_init() and gdk_threads_init() before executing
+ * any other GTK+ or GDK functions in a threaded GTK+ program.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.)
+ *
+ * A minimal main program for a threaded GTK+ application
+ * looks like:
+ * <informalexample>
+ * <programlisting role="C">
+ * int
+ * main (int argc, char *argv[])
+ * {
+ * GtkWidget *window;
+ *
+ * g_thread_init (NULL);
+ * gdk_threads_init (<!-- -->);
+ * gdk_threads_enter (<!-- -->);
+ *
+ * gtk_init (&argc, &argv);
+ *
+ * window = create_window (<!-- -->);
+ * gtk_widget_show (window);
+ *
+ * gtk_main (<!-- -->);
+ * gdk_threads_leave (<!-- -->);
+ *
+ * return 0;
+ * }
+ * </programlisting>
+ * </informalexample>
+ *
+ * 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.
+ *
+ * Erik Mouw contributed the following code example to
+ * illustrate how to use threads within GTK+ programs.
+ * <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.
+ * *
+ * *<!---->/
+ *
+ * #include <stdio.h>
+ * #include <stdlib.h>
+ * #include <unistd.h>
+ * #include <time.h>
+ * #include <gtk/gtk.h>
+ * #include <glib.h>
+ * #include <pthread.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(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(&argc, &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 (&yes_tid, NULL, argument_thread, &yes_args);
+ *
+ * no_args.label = label;
+ * no_args.what = NO_IT_IS_NOT;
+ * pthread_create (&no_tid, NULL, argument_thread, &no_args);
+ *
+ * /<!---->* enter the GTK main loop *<!---->/
+ * gtk_main (<!-- -->);
+ * gdk_threads_leave (<!-- -->);
+ *
+ * return 0;
+ * }
+ * </programlisting>
+ * </informalexample>
+ */
+
+
+/**
+ * gdk_threads_enter:
+ *
+ * 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.
+ */
void
gdk_threads_enter (void)
{
@@ -406,6 +644,11 @@ gdk_threads_enter (void)
(*gdk_threads_lock) ();
}
+/**
+ * gdk_threads_leave:
+ *
+ * Leaves a critical region begun with gdk_threads_enter().
+ */
void
gdk_threads_leave (void)
{
@@ -429,7 +672,7 @@ gdk_threads_impl_unlock (void)
/**
* gdk_threads_init:
- *
+ *
* Initializes GDK so that it can be used from multiple threads
* in conjunction with gdk_threads_enter() and gdk_threads_leave().
* g_thread_init() must be called previous to this function.