Chapter 3. Multi-/Super-threaded tree

Table of Contents

The main loop interface
Threads in general
Pulling threads of thread pool
Worker-threads to do tic-less parallelism
Asynchronously destroy objects
Poll for file descriptors
Launching tasks
Mutex and condition manager
Async message delivery

Advanced Gtk+ Sequencer comes with an AgsThread object. It is organized as a tree structure. The API provides many functions to work with it. These threads do the ::clock event where all threads synchronize.

The AgsTaskThread runs synchronized as well but is going to be waited after syncing to run all tasks. The AgsTask signal ::launch runs asynchronous exclusively. So the task thread implements AgsAsyncQueue interface. Every thread tree shall have at toplevel a thread implementing AgsMainLoop interface.

There is an object call AgsThreadPool serving prelaunched threads. It returns on pull AgsReturnableThread instances. They can be used with a callback ::safe-run.

There is a interface to implement by your application context. Thus the AgsConcurrencyProvider interface is used. It has some common get/set functions to do basic multi-threaded work by well defined objects.

The main loop interface

AgsMainLoop should be implemented by toplevel threads. Within a thread tree this is the topmost element. It has various get and set methods you would expect. ::set_tic and ::get_tic is used for synchronization purpose as well ::set_last_sync and ::get_last_sync. ::get_async_queue should return an instance implementing AgsAsyncQueue eg. AgsTaskThread. ::get_application_context returns the AgsApplicationContext.

To control the AgsThread::clock signal AgsMainLoop's methods are going to be invoked. The involved functions are:

  • void ags_main_loop_set_tic(AgsMainLoop*, guint)
  • guint ags_main_loop_get_tic(AgsMainLoop*)
  • void ags_main_loop_set_last_sync(AgsMainLoop*, guint)
  • guint ags_main_loop_get_last_sync(AgsMainLoop*)

The main loop specifies some signals like ::interrupt, ::monitor and ::change-frequency. They are all related to realtime behavior of an application. Assumed you have a thread you want to run within the thread tree, but it is not mandatory to run it. With these functions you can determine if you shall pause your thread during ::interrupt signal. How many time you are allowed to consume or running at all, can be concluded by using ::monitor. In order to get notified about modified refreshing rate of your thread, listen to ::change-frequency signal.

The interface provides some other function pointers. If you want to provide AgsTaskThread to your application, use void ags_main_loop_set_async_queue(AgsMainLoop*, GObject*) and GObject* ags_main_loop_get_async_queue(AgsMainLoop*).

As it shall be implemented by AGS_TYPE_THREAD subtypes, this parent object provides a mutex to properly lock the object. You should obtain the pthread_mutex_t pointer by accessing its field:

#include <glib.h>
#include <glib-object.h>

#include <ags/libags.h>

AgsThread *thread;

pthread_mutex_t *thread_mutex;

thread = ags_thread_new(NULL);

/* get object mutex */
thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);