c++-gtk-utils: Writing multi-threaded programs using c++-gtk-utils

c++-gtk-utils

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

Writing multi-threaded programs using c++-gtk-utils

This library has been written with threading in mind. The documentation indicates which components are thread-safe and which are not: generally any components which need to be thread-safe for useful multi-threaded program design are thread-safe, or have a thread-safe option.

glib, including any glib main loop, is thread-safe provided that, if glib < 2.32 is installed, g_thread_init() has been called. Any multi-threaded program using c++-gtk-utils with glib < 2.32 will in practice want to call g_thread_init(), and prior to glib version 2.24, g_thread_init() had to be called before any other glib function. From glib version 2.24, this requirement is relaxed so that g_thread_init() can be called before any glib call is made to which thread safety is relevant (see the glib documentation for further particulars). From glib version 2.32, g_thread_init() does not need to be called for glib to be thread-safe (g_thread_init() is a no-op retained for API/ABI compatibility reasons).

The X11 backend for gtk+ and gdk is thread-aware but not of itself thread safe. With the X11 backend, gtk+ and gdk functions can be called by more than one thread if the gdk global lock is initialised by a call to gdk_threads_init() and calls to gtk+ and gdk are made within the lock by appropriate use of gdk_threads_enter() and gdk_threads_leave(). https://developer.gnome.org/gdk2/stable/gdk2-Threads.html#gdk2-Threads.description gives futher details. In a program which uses gdk_threads_enter() and gdk_threads_leave() in order to invoke the global lock, any calls to the public functions of Cgu::WinBase, and any creating of Cgu::WinBase or Cgu::MainWidgetBase objects so invoking their constructors or destroying them explicitly or implicitly and so invoking their destructors, and any calls to most public functions of Cgu::Application, must be within the global lock. With that in mind, it should be noted that any callbacks executed by Cgu::Notifier where the Notifier object is emitted() on (or operator()() invoked) by other than the main program thread, and any callbacks executed by Cgu::Callback::post(), Cgu::Thread::Future::when(), Cgu::Thread::TaskManager::make_task_when(), Cgu::Thread::TaskManager::make_task_when_full(), Cgu::Thread::TaskManager::make_task_compose(), Cgu::Thread::TaskManager::make_task_packaged_when() or Cgu::Thread::TaskManager::make_task_packaged_compose() are not executed within the global lock (so the callback function should itself invoke gdk_threads_enter()/gdk_threads_leave() where relevant).

However, from gtk+-3.6 use of the gdk global lock has been deprecated, and it is unnecessary with c++-gtk-utils because this library provides Cgu::Notifier objects and Cgu::Callback::post(), Cgu::Thread::Future::when(), Cgu::Thread::TaskManager::make_task_when(), Cgu::Thread::TaskManager::make_task_when_full(), Cgu::Thread::TaskManager::make_task_compose(), Cgu::Thread::TaskManager::make_task_packaged_when() and Cgu::Thread::TaskManager::make_task_packaged_compose() functions, which will enable a worker thread to cause a callback object to be executed by the main GUI thread. If all gtk+/gdk functions to be invoked in a program by a worker thread are invoked by a callback object executed via one of these objects or functions, the gdk global lock can be ignored, and there is no need to call gdk_threads_init(), gdk_threads_enter() or gdk_threads_leave() in the program.

Approaching program design this way will also generally result in a cleaner design and is much less error-prone. Calls to gtk+ and gdk functions would always be thread safe because they would always be made in the same thread (the main GUI thread).

The documentation on the Cgu::Thread::Thread class gives further information on the relationship between pthreads (as used by this library), GThreads and C++11/14 threads