GNU Astronomy Utilities


Previous: , Up: Multithreaded programming   [Contents][Index]


10.3.2.2 Gnuastro’s thread related functions

The POSIX Threads functions offered in the C library are very low-level and offer a great range of control over the properties of the threads. So if you are interested in customizing your tools for complicated thread applications, it is strongly encouraged to get a nice familiarity with them. Some resources were introduced in Multithreaded programming (threads.h).

However, in many cases used in astronomical data analysis, you don’t need communication between threads and each target operation can be done independently. Since such operations are very common, Gnuastro provides the tools below to facilitate the creation and management of jobs without any particular knowledge of POSIX Threads for such operations. The most interesting high-level functions of this section are the gal_threads_number and gal_threads_spin_off that identify the number of threads on the system and spin-off threads. You can see a demonstration of using these functions in Library demo - multi-threaded operation.

C struct): gal_threads_params

Structure keeping the parameters of each thread. When each thread is created, a pointer to this structure is passed to it. The params element can be the pointer to a structure defined by the user which contains all the necessary parameters to pass onto the worker function. The rest of the elements within this structure are set internally by gal_threads_spin_off and are relevant to the worker function.

struct gal_threads_params
{
  size_t            id; /* Id of this thread.                  */
  void         *params; /* User-identified pointer.            */
  size_t       *indexs; /* Target indexs given to this thread. */
  pthread_barrier_t *b; /* Barrier for all threads.            */
};
Function:
size_t
gal_threads_number ()

Return the number of threads that the operating system has available for your program. This number is usually fixed for a single machine and doesn’t change. So this function is useful when you want to run your program on different machines (with different CPUs).

Function:
void
gal_threads_spin_off (void *(*worker)(void *), void *caller_params, size_t numactions, size_t numthreads)

Distribute numactions jobs between numthreads threads and spin-off each thread by calling the worker function. The caller_params pointer will also be passed to worker as part of the gal_threads_params structure. For a fully working example of this function, please see Library demo - multi-threaded operation.

Function:
void
gal_threads_attr_barrier_init (pthread_attr_t *attr, pthread_barrier_t *b, size_t limit)

This is a low-level function in case you don’t want to use gal_threads_spin_off. It will initialize the general thread attribute attr and the barrier b with limit threads to wait behind the barrier. For maximum efficiency, the threads initialized with this function will be detached. Therefore no communication is possible between these threads and in particular pthread_join won’t work on these threads. You have to use the barrier constructs to wait for all threads to finish.

Function:
void
gal_threads_dist_in_threads (size_t numactions, size_t numthreads, size_t **outthrds, size_t *outthrdcols)

This is a low-level function in case you don’t want to use gal_threads_spin_off. Identify the “index”es (starting from 0) of the actions to be done on each thread in the outthrds array. outthrds is treated as a 2D array with numthreads rows and outthrdcols columns. The indexs in each row, identify the actions that should be done by one thread. Please see the explanation below to understand the purpose of this operation.

Let’s assume you have \(A\) actions (where there is only one function and the input values differ for each action) and \(T\) threads available to the system with \(A>T\) (common values for these two would be \(A>1000\) and \(T<10\)). Spinning off a thread is not a cheap job and requires a significant number of CPU cycles. Therefore, creating \(A\) threads is not the best way to address such a problem. The most efficient way to manage the actions is such that only \(T\) threads are created, and each thread works on a list of actions identified for it in series (one after the other). This way your CPU will get all the actions done with minimal overhead.

The purpose of this function is to do what we explained above: each row in the outthrds array contains the indexs of actions which must be done by one thread. outthrds contains outthrdcols columns. In using outthrds, you don’t have to know the number of columns. The GAL_BLANK_SIZE_T macro has a role very similar to a string’s \0: every row finishes with this macro, so can easily stop parsing the indexes in the row when you confront it. Please see the example program in tests/lib/multithread.c for a demonstration.


Previous: , Up: Multithreaded programming   [Contents][Index]