GDK 3 Reference Manual: Threads

## Threads Threads — Functions for using GDK in multi-threaded programs |

## Synopsis

    #include <gdk/gdk.h>

    #define             GDK_THREADS_ENTER
    #define             GDK_THREADS_LEAVE
    void                gdk_threads_init                    (void);
    void                gdk_threads_enter                   (void);
    void                gdk_threads_leave                   (void);
    void                gdk_threads_set_lock_functions      (GCallback enter_fn,
                                                             GCallback leave_fn);
    guint               gdk_threads_add_idle                (GSourceFunc function,
                                                             gpointer data);
    guint               gdk_threads_add_idle_full           (gint priority,
                                                             GSourceFunc function,
                                                             gpointer data,
                                                             GDestroyNotify notify);
    guint               gdk_threads_add_timeout             (guint interval,
                                                             GSourceFunc function,
                                                             gpointer data);
    guint               gdk_threads_add_timeout_full        (gint priority,
                                                             guint interval,
                                                             GSourceFunc function,
                                                             gpointer data,
                                                             GDestroyNotify notify);
    guint               gdk_threads_add_timeout_seconds     (guint interval,
                                                             GSourceFunc function,
                                                             gpointer data);
    guint               gdk_threads_add_timeout_seconds_full
                                                            (gint priority,
                                                             guint interval,
                                                             GSourceFunc function,
                                                             gpointer data,
                                                             GDestroyNotify notify);

## Description

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.

You must call `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 "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 must 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:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    int
    main (int argc, char *argv[])
    {
      GtkWidget *window;

      gdk_threads_init ();
      gdk_threads_enter ();

      gtk_init (&argc, &argv);

      window = create_window ();
      gtk_widget_show (window);

      gtk_main ();
      gdk_threads_leave ();

      return 0;
    }

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.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    /*-------------------------------------------------------------------------
     * 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 */
      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;
    }

Unfortunately, all of the above documentation holds with the X11 backend only. With the Win32 or Quartz backends, GDK and GTK+ calls must occur only in the main thread (see below). When using Python, even on X11 combining the GDK lock with other locks such as the Python global interpreter lock can be complicated.

For these reasons, the threading support has been deprecated in GTK+ 3.6. Instead of calling GTK+ directly from multiple threads, it is recommended to use `g_idle_add()`, `g_main_context_invoke()` and similar functions to make these calls from the main thread instead. The main thread is the thread which has called `gtk_init()` and is running the GTK+ mainloop. GTK+ itself will continue to use the GDK lock internally as long as the deprecated functionality is still available, and other libraries should probably do the same.

## Details

### GDK_THREADS_ENTER

    #define GDK_THREADS_ENTER() gdk_threads_enter()

### Warning

`GDK_THREADS_ENTER` has been deprecated since version 3.6 and should not be used in newly-written code. Use `g_main_context_invoke()`, `g_idle_add()` and related functions if you need to schedule GTK+ calls from other threads.

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.

### GDK_THREADS_LEAVE

    #define GDK_THREADS_LEAVE() gdk_threads_leave()

### Warning

`GDK_THREADS_LEAVE` has been deprecated since version 3.6 and should not be used in newly-written code. Deprecated in 3.6.

This macro marks the end of a critical section begun with GDK_THREADS_ENTER.

### gdk_threads_init ()

    void                gdk_threads_init                    (void);

### Warning

`gdk_threads_init` has been deprecated since version 3.6 and should not be used in newly-written code. All GDK and GTK+ calls should be made from the main thread

Initializes GDK so that it can be used from multiple threads in conjunction with `gdk_threads_enter()` and `gdk_threads_leave()`.

This call must be made before any use of the main loop from GTK+; to be safe, call it before `gtk_init()`.

### gdk_threads_enter ()

    void                gdk_threads_enter                   (void);

### Warning

`gdk_threads_enter` has been deprecated since version 3.6 and should not be used in newly-written code. All GDK and GTK+ calls should be made from the main thread

This function 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.

### gdk_threads_leave ()

    void                gdk_threads_leave                   (void);

### Warning

`gdk_threads_leave` has been deprecated since version 3.6 and should not be used in newly-written code. All GDK and GTK+ calls should be made from the main thread

Leaves a critical region begun with `gdk_threads_enter()`.

### gdk_threads_set_lock_functions ()

    void                gdk_threads_set_lock_functions      (GCallback enter_fn,
                                                             GCallback leave_fn);

### Warning

`gdk_threads_set_lock_functions` has been deprecated since version 3.6 and should not be used in newly-written code. All GDK and GTK+ calls should be made from the main thread

Allows the application to replace the standard method that GDK uses to protect its data structures. Normally, GDK creates a single GMutex that is locked by `gdk_threads_enter()`, and released by `gdk_threads_leave()`; using this function an application provides, instead, a function `enter_fn` that is called by `gdk_threads_enter()` and a function `leave_fn` that is called by `gdk_threads_leave()`.

The functions must provide at least same locking functionality as the default implementation, but can also do extra application specific processing.

As an example, consider an application that has its own recursive lock that when held, holds the GTK+ lock as well. When GTK+ unlocks the GTK+ lock when entering a recursive main loop, the application must temporarily release its lock as well.

Most threaded GTK+ apps won't need to use this method.

This method must be called before `gdk_threads_init()`, and cannot be called multiple times.

`enter_fn` : | function called to guard GDK
`leave_fn` : | function called to release the guard

Since 2.4

### gdk_threads_add_idle ()

    guint               gdk_threads_add_idle                (GSourceFunc function,
                                                             gpointer data);

A wrapper for the common usage of `gdk_threads_add_idle_full()` assigning the default priority, G_PRIORITY_DEFAULT_IDLE.

See `gdk_threads_add_idle_full()`.

`function` : | function to call
`data` : | data to pass to `function`
Returns : | the ID (greater than 0) of the event source.

Since 2.12

### gdk_threads_add_idle_full ()

    guint               gdk_threads_add_idle_full           (gint priority,
                                                             GSourceFunc function,
                                                             gpointer data,
                                                             GDestroyNotify notify);

### gdk_threads_add_timeout ()

    guint               gdk_threads_add_timeout             (guint interval,
                                                             GSourceFunc function,
                                                             gpointer data);

A wrapper for the common usage of `gdk_threads_add_timeout_full()` assigning the default priority, G_PRIORITY_DEFAULT.

See `gdk_threads_add_timeout_full()`.

`interval` : | the time between calls to the function, in milliseconds (1/1000ths of a second)
`function` : | function to call
`data` : | data to pass to `function`
Returns : | the ID (greater than 0) of the event source.

Since 2.12

### gdk_threads_add_timeout_full ()

    guint               gdk_threads_add_timeout_full        (gint priority,
                                                             guint interval,
                                                             GSourceFunc function,
                                                             gpointer data,
                                                             GDestroyNotify notify);

### gdk_threads_add_timeout_seconds ()

    guint               gdk_threads_add_timeout_seconds     (guint interval,
                                                             GSourceFunc function,
                                                             gpointer data);

A wrapper for the common usage of `gdk_threads_add_timeout_seconds_full()` assigning the default priority, G_PRIORITY_DEFAULT.

For details, see `gdk_threads_add_timeout_full()`.

`interval` : | the time between calls to the function, in seconds
`function` : | function to call
`data` : | data to pass to `function`
Returns : | the ID (greater than 0) of the event source.

Since 2.14

### gdk_threads_add_timeout_seconds_full ()

    guint               gdk_threads_add_timeout_seconds_full
                                                            (gint priority,
                                                             guint interval,
                                                             GSourceFunc function,
                                                             gpointer data,
                                                             GDestroyNotify notify);