RE: Pthreads with GTK 1.2



On 10-Jan-2003 Boris wrote:
I am trying to show/hide a window from a separated thread. This thread was
created with pthread_create function. The show action works fine.  The
problem is the hide action, it never launchs, my window
is visible all the time.
Your question is answered in section 5.2 of the FAQ. On my debian-box this
can be found at
file:///usr/share/doc/libgtk1.2-doc/faq-html/gtkfaq-5.html#ss5.2
Of course, you can also find it on the net.

Bye,
Wolfgang Koebler


5.2 Is GTK+ thread safe? How do I write multi-threaded GTK+ applications?

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.

When GLib is intialized to be thread-safe, GTK+ is thread aware. 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.

A minimal main program for a threaded GTK+ application looks like:

int
main (int argc, char *argv[])
{
  GtkWidget *window;

  g_thread_init(NULL);
  gtk_init(&argc, &argv);

  window = create_window();
  gtk_widget_show(window);

  gdk_threads_enter();
  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.

/*-------------------------------------------------------------------------
 * 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);

  /* 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);

  gtk_signal_connect(GTK_OBJECT (window), "destroy",
                     GTK_SIGNAL_FUNC(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 */
  gdk_threads_enter();
  gtk_main();
  gdk_threads_leave();

  return(0);
}






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]