This is a simple framework for using GTK+ in threaded programs.
It is based on the ideas of Rob Browning and M. Stekelenburg.

Usage:

 Call gtk_threads_init() after gtk_init() and before creating
 any GTK-using threads.

 Call gtk_threads_enter() before calling any GTK operations,
 and gtk_threads_leave() after finishing the GTK operations.

 To start the main loop, use gtk_threads_main() instead of 
 gtk_main().

 In any callbacks from your main loop, if you want to release
 the GTK lock, call gtk_threads_leave_main() at the beginning,
 and gtk_threads_enter_main() at the end.

The test program:

 $ make
 $ ./testthreads

Caveats:

 You probably should compile GTK+ with -D_REENTRANT
 
 Calls to gtk_thread_main() should be made from only one thread.

 The context for GTK+ calls with like gtk_widget_push_colormap
 will be shared among all threads.

 This is my first attempt at writing any careful thread-locking code.

Theory:

 All GTK+ access is protected by a single mutex lock. The
 lock is acquired by the mainloop on entry, and temporarily
 released:
 
  a) By an explicit call to gtk_threads_leave_main()
  b) When another thread wants the lock and signals this by
     writing a byte into a pipe.

Performance:

 On a Pentium 133, Linux 2.0.33, LinuxThreads, the code seems
 to be good for about 5,000 switches to and from the main event
 loop / second.

Future directions:

 Could blocking on the signalling pipe be cleverly used to
 remove some of the pthread_cond_waits?

 Add this type of basic support directly to GTK+.

 If the lock was removed entirely around GTK's select(),
 calls from subsidiary threads would be more efficient. On
 the other hand, it would mean unlocking and locking around
 each select(), so event handling would become less efficient.

 Add #ifdef'd enter/leave around all GTK+ calls.

 Make contextual information in GTK+ per-thread.

 Use finer-grained locks.

Owen Taylor
May 10, 1998