docs: Move documentation to inline comments: gdkthreads
This commit is contained in:
parent
7524d5fcbe
commit
dd2db852cc
1
docs/reference/gdk/tmpl/.gitignore
vendored
1
docs/reference/gdk/tmpl/.gitignore
vendored
@ -15,5 +15,6 @@ properties.sgml
|
|||||||
pixbufs.sgml
|
pixbufs.sgml
|
||||||
regions.sgml
|
regions.sgml
|
||||||
selections.sgml
|
selections.sgml
|
||||||
|
threads.sgml
|
||||||
visuals.sgml
|
visuals.sgml
|
||||||
windows.sgml
|
windows.sgml
|
||||||
|
@ -1,381 +0,0 @@
|
|||||||
<!-- ##### SECTION Title ##### -->
|
|
||||||
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 — 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 (&argc, &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 <J.A.K.Mouw@its.tudelft.nl>
|
|
||||||
* Description: GTK threads example.
|
|
||||||
* Created at: Sun Oct 17 21:27:09 1999
|
|
||||||
* Modified by: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
|
|
||||||
* 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>
|
|
||||||
|
|
||||||
<!-- ##### 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:
|
|
||||||
|
|
||||||
|
|
||||||
<!-- ##### 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:
|
|
||||||
|
|
||||||
|
|
243
gdk/gdk.c
243
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 — 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 <J.A.K.Mouw@its.tudelft.nl>
|
||||||
|
* * Description: GTK threads example.
|
||||||
|
* * Created at: Sun Oct 17 21:27:09 1999
|
||||||
|
* * Modified by: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
|
||||||
|
* * 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
|
void
|
||||||
gdk_threads_enter (void)
|
gdk_threads_enter (void)
|
||||||
{
|
{
|
||||||
@ -406,6 +644,11 @@ gdk_threads_enter (void)
|
|||||||
(*gdk_threads_lock) ();
|
(*gdk_threads_lock) ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gdk_threads_leave:
|
||||||
|
*
|
||||||
|
* Leaves a critical region begun with gdk_threads_enter().
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
gdk_threads_leave (void)
|
gdk_threads_leave (void)
|
||||||
{
|
{
|
||||||
|
@ -64,7 +64,24 @@ guint gdk_threads_add_timeout_seconds (guint interval,
|
|||||||
GSourceFunc function,
|
GSourceFunc function,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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. 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.
|
||||||
|
*/
|
||||||
#define GDK_THREADS_ENTER() gdk_threads_enter()
|
#define GDK_THREADS_ENTER() gdk_threads_enter()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GDK_THREADS_LEAVE:
|
||||||
|
*
|
||||||
|
* This macro marks the end of a critical section
|
||||||
|
* begun with #GDK_THREADS_ENTER.
|
||||||
|
*/
|
||||||
#define GDK_THREADS_LEAVE() gdk_threads_leave()
|
#define GDK_THREADS_LEAVE() gdk_threads_leave()
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
Loading…
Reference in New Issue
Block a user