# Multi-/Super-threaded tree

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 AgsTaskLauncher runs synchronized as well but is going to be waited after syncing to run all tasks. The AgsTask signal ::launch runs asynchronous exclusively. 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.

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

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 GRecMutex pointer by accessing its field:

## Threads in general

Libags provides a thread wrapper built on top of GLib's threading API. The AgsThread object synchronizes the thread tree by AgsThread::clock() event. It is somekind of parallelism trap.

All threads within tree synchronize to AgsThread:max-precision per second, because all threads shall have the very same time running in parallel. I talk of tic-based parallelism, with a max-precision of 1000 Hz, each thread synchronizes 1000 times within tree. Giving you strong semantics to compute a deterministic result in a multi-threaded fashion.

Since we want to run tasks exclusively without any interference from competing threads. There is a mutex lock involved just after synchronization and then invokes ags_task_launcher_sync_run(). Be aware the conditional lock can be evaluate to true for many threads.

After how many tics the flow is repeated depends on samplerate and buffer size. If you have an AgsThread with max-precision 1000, samplerate of 44100 common for audio CDs and a buffer size of 512 frames, then the delay until its repeated calculates as following:

### Calculating tic delay

    	tic_delay = 1000.0 / 44100.0 * 512.0; // 11.609977324263039

As you might have pre-/post-synchronization needing 3 tics to do its work you get 8 unused tics.

Pre-synchronization is used for reading from soundcard or MIDI device. The intermediate tic does the actual audio processing. Post-synchronization is used by outputing to soundcard or exporting to audio file.

Within thread tree context you have to take care not to hang it up with a dead-lock. Usually you have to use the :start_queue to start threads. Alternatively you may want to use `void ags_thread_start(AgsThread*)`. Use :start_cond, which is protect it with :start_mutex, to notify about running thread.

The following example creates a thread and does add an other thread to :start_queue. This causes it to be started as well. Note you want to access :start_queue using :start_mutex to avoid data races. But there is a convience function which does it for you.

### Starting threads

There many other functions not covered like mutex wrappers ags_thread_lock() and ags_thread_unlock(). As doing a closer look to the API there are functions to lock different parts of the tree. But all these functions should be carefully used, since you might run into a dead-lock.

To find a specific thread type use ags_thread_find(). You can use ags_thread_self() to retrieve your own running thread in case your using Advanced Gtk+ Sequencer thread wrapper.

## Pulling threads of thread pool

AgsThreadPool serves you instantiated and running threads. To pull an AgsReturnableThread issue ags_thread_pool_pull(). The following example does instantiate a thread pool and starts it. After, it pulls two threads and the callbacks are invoked.

### Pulling threads of thread-pool

## Worker-threads to do tic-less parallelism

Worker threads are used to perform heavy load tasks that run completely asynchronous. This means they don't do any sync with the tree. You start worker threads like any other thread by calling `void ags_thread_start(AgsThread*)` or `void ags_thread_stop(AgsThread*)` to stop it.

The AgsWorkerThread overrides ::start of AgsThread class and won't do any synchronization. The worker implementation is responsible to delay computation by calling usleep() or nanosleep().

You can either connect to the ::do-poll signal or inherit of the AgsWorkerThread object. This requires to override ::do-poll.

### Asynchronously destroy objects

AgsDestroyWorker is intended to unref or free objects asynchrously. Note the use of this worker for one certain instance, requires it to do it throughout with the worker for all unref calls. Else you would probably end in a data-race ending in accessing a freed instance. This can especially happen as using g_object_run_dispose().

The destroy function takes exactly one parameter like g_free() or g_object_unref(). To add an entry call ags_destroy_worker_add(). The first parameter is the worker, second the pointer to free/unref and third the destroy function.

## Launching tasks

It's for thread-safety for sure to run tasks asynchronously exclusive. This means what ever you do it's safe exceptional in view of third-party libraries that might have their own threads. To do your own task you should inherit AgsTask base object and implement ::launch. This signal is invoked after syncing the thread tree.

You can use either ags_task_launcher_add_task() or ags_task_launcher_add_task_all() to add one respectively a GList of tasks. The task shall report failures by calling ::failure signal.

## Async message delivery

AgsMessageDelivery is a singleton. In order to get the instance of it call `AgsMessageDelivery* ags_message_delivery_get_instance()`. The library routines only provide messages until you have added an AgsMessageQueue with the appropriate namespace.

- libags - namespace used by &libagsso;, &libagsthreadso; and &libagsserverso;
- libags-audio - namespace used by &libagsaudioso;

As you usually have one object or widget mapped to a specific object, you can poll the queue by `guint g_timeout_add(guint, GSourceFunc, gpointer)`. Then forward the event as you like. GSequencer does look for matching messages by sender using following `GList* ags_message_queue_find_sender(AgsMessageQueue*, GObject*)`. This not at least because the recipient is most of the time not defined.