GTK+ Threading

Published: Tuesday, 20 July 2010 13:13

I"ve just been working with  GTK+ , a GUI toolkit for C/Linux - but ported to pretty much everything.  Initial impressions are quite good, although I am starting to miss Qt/Creator Anyhow, I hit the age-old problem quite quickly.  The GUI thread just isn't enough.  To start with, I just slapped in a "normal" thread (pthread_t) but when the time came to update the GUI, things started to go pete tong.  Here is how I sorted it;

GTK+ is described as "thread aware" rather than "thread safe" so you need to be a bit careful, although after a little investigation it gets very simple.

Firstly, let GLib/GTK know that it may need to share (these should be done FIRST and in this order before any other GLib code gets run);

  1. g_thread_init(NULL);
  2. gdk_threads_init();

Then you can start a thread;

  1. GError *gError = NULL;
  2. g_thread_create(my_thread, pMyData, FALSE, &Error);

The prototype of the thread function you want to call should look something like this;

  1. void *my_thread(void *ptr);

Finally all critical code should be wrapped in;

  1. gdk_threads_enter();
  2. // and

  3. gdk_threads_leave();

INCLUDING gtk_main();

These functions are basically mutex macros which stop two threads accessing the same data at the same time.

Compile in the same way as any other GTK+ program, but ensure the following is added to the compiler options;

  1. -lgthread-2.0

Here is a very simple example for clarification;

  1. #include
  2. // Label that we will change the text of
  3. GtkWidget *label;
  4. // The thread.
  5. void *my_thread(void *pData)
  6. {
  7. gdk_threads_enter();
  8. gtk_label_set_text(GTK_LABEL(label), "Not My Label");
  9. gdk_threads_leave();
  10. return 0;
  11. }
  12. int main(int argc, char *argv[])
  13. {
  14. // Thread safe
  15. g_thread_init(NULL);
  16. gdk_threads_init();
  17. // Load GUI.
  18. gtk_init (&argc, &argv);
  19. GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  20. // Simple label
  21. label = gtk_label_new("My Label");
  22. gtk_container_add(GTK_CONTAINER(window), label);
  23. gtk_widget_show(label);
  24. gtk_widget_show(window);
  25. // Load the thread.
  26. GError *error = NULL;
  27. void *pData = 0x00;
  28. if (!g_thread_create(my_thread, pData, FALSE, &error))
  29. {
  30. g_printerr ("Failed to create thread: %sn", error->message);
  31. return 1;
  32. }
  33. // Run window.
  34. gdk_threads_enter();
  35. gtk_main();
  36. gdk_threads_leave();
  37. return 0;
  38. }

It can be compiled using the following;

  1. gcc -Wall -g shoal_test.c `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0` -lgthread-2.0

Its as simple as that.  I hope it helps someone!