gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master 1a266dd 1/2: threads.h documented, pthread_bar


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master 1a266dd 1/2: threads.h documented, pthread_barrier usable outside
Date: Fri, 23 Sep 2016 11:07:28 +0000 (UTC)

branch: master
commit 1a266dd3be025def43509a1b9afe7039e0b85b10
Author: Mohammad Akhlaghi <address@hidden>
Commit: Mohammad Akhlaghi <address@hidden>

    threads.h documented, pthread_barrier usable outside
    
    The inclusion of the `pthread_barrier' definitions and declarations in
    `lib/gnuastro/threads.h' and `lib/threads.c' was not suitable for
    libraries. Because the `HAVE_PTHREAD_BARRIER' macro that was used to define
    them was defined in `config.h' which is not installed. So if someone's
    operating system doesn't have `pthread_barrier' constructs, none of
    Gnuastro's threading will work for them. So several new things were added
    with this commit:
    
     - A new `IN_GNUASTRO_BUILD' macro is now defined in `config.h' which will
       let the headers know that they are in the pre-installation environment,
       not in the post-installation.
    
     - The `GAL_GNUASTRO_PTHREAD_BARRIER' was added to `lib/gnuastro.h.in' as
       another one of the installation parameters that installed headers should
       know about.
    
     - The `pthread_barrier' functions and structures are now only defined (in
       the `.c' and `.h' files) when `GAL_GNUASTRO_PTHREAD_BARRIER == 0'.
    
     - A test was added to `make check' to test the compiling and building of a
       multi-threaded program on the user's system. This can be useful as a
       tutorial for users to easily build multi-threaded programs and also
       allow users to widely test this feature easily as part of the checking
       package.
    
    The declarations and definitions of `threads.h' are also now fully
    documented within the book. In the process, some variables in the source
    were also renamed to be more descriptive of their nature.
---
 configure.ac            |   21 +++-
 doc/gnuastro.texi       |  278 +++++++++++++++++++++++++++++++++++++----------
 lib/Makefile.am         |    4 +-
 lib/gnuastro/threads.h  |   22 +++-
 lib/threads.c           |   29 ++---
 tests/Makefile.am       |    3 +-
 tests/lib/multithread.c |  155 ++++++++++++++++++++++++++
 7 files changed, 430 insertions(+), 82 deletions(-)

diff --git a/configure.ac b/configure.ac
index baafa55..6da5f20 100644
--- a/configure.ac
+++ b/configure.ac
@@ -79,6 +79,20 @@ LT_INIT
 
 
 
+# This macro will let the libraries know that we are now in the Gnuastro
+# build system, not on the user's system. While we are building Gnuastro,
+# we have the important installation information in `config.h'. But in the
+# user's own programs, this information is defined in
+# `gnuastro/gnuastro.h'. With this macro, the installed headers can decide
+# if the latter should be included or not. Note that `gnuastro/gnuastro.h'
+# is only built at installation time and doesn't exist when building
+# Gnuastro. Therefore, this macro must not be defined in a user's program.
+AC_DEFINE([IN_GNUASTRO_BUILD], [1], [In building, not usage])
+
+
+
+
+
 # Generic flags for all subdirectories. Note that when order matters, we
 # want the user values to be set (and thus used) after the default
 # values. The "AM_" versions of these variables will be confined to the
@@ -134,8 +148,11 @@ AC_SEARCH_LIBS([wcspih], [wcs], [],
 AC_CHECK_LIB([wcs], [wcslib_version],
              [AC_DEFINE([HAVE_WCSLIBVERSION], [1], [Has wcslib_version])],
              [], [-lcfitsio -lm])
-AC_CHECK_LIB([pthread], [pthread_barrier_wait],
-             [AC_DEFINE([HAVE_PTHREAD_BARRIER], [1], [Has pthread_barrier])])
+AC_CHECK_LIB([pthread], [pthread_barrier_wait], [has_pthread_barrier=1],
+             [has_pthread_barrier=0])
+AC_DEFINE_UNQUOTED([GAL_GNUASTRO_PTHREAD_BARRIER], [$has_pthread_barrier],
+                   [System has pthread_barrier])
+AC_SUBST(HAS_PTHREAD_BARRIER, [$has_pthread_barrier])
 
 
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index daf7c20..0964ba7 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -508,7 +508,7 @@ Review of library fundamentals
 
 Gnuastro library
 
-* Overall package::             Macros for the whole package.
+* Installation information::    General information about the installation.
 * Array manipulation::          Functions for manipulating arrays.
 * Bounding box::                Finding the bounding box.
 * FITS files::                  Working with FITS datat.
@@ -518,6 +518,7 @@ Gnuastro library
 * Qsort functions::             Helper functions for Qsort.
 * Spatial convolution::         Doing spatial convolution on an image
 * Statistical operations::      Functions for basic statistics.
+* Multithreaded programming::   Facilitating use of pthreads.
 
 FITS files (@file{fits.h})
 
@@ -525,6 +526,11 @@ FITS files (@file{fits.h})
 * FITS macros and data structures::  Gnuastro FITS related macros and 
structures.
 * FITS functions::              Functions to work on FITS data.
 
+Multithreaded programming (@file{threads.h})
+
+* Implementation of pthread_barrier::  Some systems don't have pthread_barrier
+* Gnuastro's thread related functions::  Functions for managing threads.
+
 Developing
 
 * Why C::                       Why Gnuastro is designed in C.
@@ -543,7 +549,6 @@ Program source
 
 * Mandatory source code files::  How the source files of each program are 
managed.
 * Coding conventions::          Basic conventions for coding structure.
-* Multithreaded programming::   Gnuastro's multithreaded programming style.
 * Documentation::               Documentation is an integral part of Gnuastro.
 * The TEMPLATE utility::        A template to create new utilities.
 
@@ -3442,7 +3447,7 @@ complete names also enable you to easily search for the 
programs.
 To facilitate typing the names in, we suggest using the shell
 auto-complete. With this facility you can find the executable you want
 very easily. It is very similar to file name completion in the
-shell. For example, simply by typing the letters bellow (where
+shell. For example, simply by typing the letters below (where
 @key{[TAB]} stands for the Tab key on your keyboard)
 
 @example
@@ -14761,7 +14766,7 @@ problems. It will stabilize with the removal of this 
notice. Check the
 @end cartouche
 
 @menu
-* Overall package::             Macros for the whole package.
+* Installation information::    General information about the installation.
 * Array manipulation::          Functions for manipulating arrays.
 * Bounding box::                Finding the bounding box.
 * FITS files::                  Working with FITS datat.
@@ -14771,18 +14776,19 @@ problems. It will stabilize with the removal of this 
notice. Check the
 * Qsort functions::             Helper functions for Qsort.
 * Spatial convolution::         Doing spatial convolution on an image
 * Statistical operations::      Functions for basic statistics.
+* Multithreaded programming::   Facilitating use of pthreads.
 @end menu
 
address@hidden Overall package, Array manipulation, Gnuastro library, Gnuastro 
library
address@hidden Overall package (@file{gnuastro.h})
address@hidden Installation information, Array manipulation, Gnuastro library, 
Gnuastro library
address@hidden Installation information (@file{gnuastro.h})
 
 The @file{gnuastro/gnuastro.h} header contains information about the full
-Gnuastro package. Gnuastro developers should note that this is the only
-header that is not available within Gnuastro, it is only available to a
-Gnuastro library user @emph{after} installation. Within Gnuastro,
address@hidden (which is included in every Gnuastro @file{.c} file, see
address@hidden conventions}) should have more than enough information about
-the overall Gnuastro installation.
+Gnuastro installation on your system. Gnuastro developers should note that
+this is the only header that is not available within Gnuastro, it is only
+available to a Gnuastro library user @emph{after} installation. Within
+Gnuastro, @file{config.h} (which is included in every Gnuastro @file{.c}
+file, see @ref{Coding conventions}) should have more than enough
+information about the overall Gnuastro installation.
 
 @deffn Macro GAL_GNUASTRO_VERSION
 This macro can be used as a string
@@ -14803,8 +14809,16 @@ char *gnuastro_version=GAL_GNUASTRO_VERSION;
 @end deffn
 
 
address@hidden Macro GAL_GNUASTRO_PTHREAD_BARRIER
+The POSIX threads standard define barriers as an optional
+requirement. Therefore, some operating systems choose to not include
+it. While installing Gnuastro, we check if your system has this construct
+and if so, we give this macro a value of @code{1}, otherwise it will have a
+value of @code{0}. see @ref{Implementation of pthread_barrier} for more.
address@hidden deffn
+
 
address@hidden Array manipulation, Bounding box, Overall package, Gnuastro 
library
address@hidden Array manipulation, Bounding box, Installation information, 
Gnuastro library
 @subsection Array manipulation (@file{array.h})
 
 When working on arrays, certain operations are commonly necessary. It is
@@ -16339,15 +16353,22 @@ will be allocated for the output and the convolved 
image will be stored in
 @end deftypefun
 
 
address@hidden Statistical operations,  , Spatial convolution, Gnuastro library
+
+
+
address@hidden Statistical operations, Multithreaded programming, Spatial 
convolution, Gnuastro library
 @subsection Statistical operations (@file{statistics.h})
 
 This header includes a large variety of very basic statistical operators
 for various data types. Please note that we expect to greatly simplify the
-functions here for easier and more general usage in future releases. Since
-these functions are used in various parts of Gnuastro for multiple
-purposes, in this first library release (Gnuastro 0.2), there might be
-parallels, or non-homogenous arguments.
+functions here for easier and more general usage in future
+releases. Ideally, they should be completely removed and the GNU Scientific
+Library's functions should be used. Since these functions are used in
+various parts of Gnuastro for multiple purposes, in this first library
+release (Gnuastro 0.2), there might be parallels, or non-homogenous
+arguments. Such situations arise here because of the history of Gnuastro:
+the libraries gew out of the utilities, so it will take a little while to
+correct.
 
 @deffn Structure GAL_STATISTICS_MAX_SIG_CLIP_CONVERGE
 The maximum number of times to try for @mymath{\sigma}-clipping (see
@@ -16637,6 +16658,181 @@ ApJS 220, 1. arXiv:1505.01664).
 
 
 
address@hidden Multithreaded programming,  , Statistical operations, Gnuastro 
library
address@hidden Multithreaded programming (@file{threads.h})
+
address@hidden Multithreaded programming
+In modern times, newer CPU generations don't have significantly higher
+frequencies any more. However, CPUs are being manufactured with more cores,
+enabling more than one operation (thread) at each instant. This can be very
+useful to speed up many apsects of processing and in particular image
+processing.
+
+Most of the programs in Gnuastro utilize multi-threaded programming for the
+CPU intensive processing steps. This can potentially lead to a significant
+decrease in the running time of a program, see @ref{A note on threads}. In
+terms of reading the code, you don't need to know anything about
+multi-threaded programming. You can simply follow the case where only one
+thread is to be used. In these cases, threads are not used and can be
+completely ignored. To write multi-threaded programs, the thread helper
+functions of @ref{Gnuastro's thread related functions}, you can greatly
+simplify a the process of spinning-off threads.
+
address@hidden POSIX threads library
address@hidden Lawrence Livermore National Laboratory
+At the time K&R's book was written, using threads was not common, so C's
+threading capabilities aren't introduced there. We use POSIX threads for
+multi-threaded programming, defined in the @file{pthread.h} system wide
+header. There are various resources for learning to use POSIX threads, the
+excellent tutorial from
address@hidden://computing.llnl.gov/tutorials/pthreads/, LLNL} is a very good
+start.  The book `Advanced programming in the Unix
+environment'@footnote{Don't let the title scare you! The two chapters on
+Multi-threaded programming are very self-sufficient and don't need any more
+knowledge than K&R.}, by Richard Stevens and Stephen Rago, Addison-Wesley,
+2013 (Third edition) also has two chapters explaining the POSIX thread
+constructs which can be very helpful.
+
address@hidden OpenMP
+An alternative to POSIX threads was OpenMP, but POSIX threads are low
+level, allowing much more control, while being easier to understand, see
address@hidden C}. All the situations where threads are used are completely
+independent with minimal need of coordination between the threads.  Such
+problems are known as ``embarrassingly parallel'' problems. They are some
+of the simplest problems to solve with threads and also the ones that
+benefit most from threads, see the LLNL
address@hidden@url{https://computing.llnl.gov/tutorials/parallel_comp/}}.
+
+One very useful POSIX threads concept is
address@hidden Unfortunately, it is only an optional feature in
+the POSIX standard, so some operating systems don't include it. Therefore
+in @ref{Implementation of pthread_barrier}, we introduce our own
+implementation. You can ignore this section if your system has this
+construct. Following that, we describe the helper functions in this header
+that can greatly simplify the initializing of a multi-threaded program, see
address@hidden's thread related functions} for more.
+
address@hidden
+* Implementation of pthread_barrier::  Some systems don't have pthread_barrier
+* Gnuastro's thread related functions::  Functions for managing threads.
address@hidden menu
+
address@hidden Implementation of pthread_barrier, Gnuastro's thread related 
functions, Multithreaded programming, Multithreaded programming
address@hidden Implementation of @code{pthread_barrier}
address@hidden POSIX threads
address@hidden pthread_barrier
+One optional feature of the POSIX Threads standard is the
address@hidden concept. It is a very useful high-level construct
+that allows for independent threads to ``wait'' behind a ``barrier'' for
+the rest after they finish. Barriers can thus greatly simplify the code in
+a multi-threaded program, so they are heavily used in Gnuastro. However,
+since its an optional feature in the POSIX standard, some operating systems
+don't include it. So to make Gnuastro portable, we have written our own
+implementation of those @code{pthread_barrier} functions.
+
+At @command{./configure} time, Gnuastro will check if
address@hidden constructs are available on your system or not. If
address@hidden is not available, our internal implementation will
+be compiled into the Gnuastro library and the definitions and declarations
+below will be usable in your code with @code{#include
+<gnuastro/threads.h>}.
+
address@hidden Type pthread_barrierattr_t
+Type to specify the attributes of a POSIX threads barrier.
address@hidden deffn
+
address@hidden Type pthread_barrier_t
+The structure defining the POSIX threads barrier.
address@hidden deffn
+
address@hidden int pthread_barrier_init (pthread_barrier_t @code{*b}, 
pthread_barrierattr_t @code{*attr}, unsigned int @code{limit})
+Initialize the POSIX threads barrier @code{b}, with the attributes
address@hidden with a total number of @code{limit} threads that must remain
+behind it. This function is called before spinning off threads.
address@hidden deftypefun
+
address@hidden int pthread_barrier_wait (pthread_barrier_t @code{*b})
+This function is called within each thread, just before it is ready to
+return. Once a thread's function hits this, it will ``wait'' until all the
+other functions are also finished.
address@hidden deftypefun
+
address@hidden int pthread_barrier_destroy (pthread_barrier_t @code{*b})
+Destroy all the information in the barrier structure. This should be called
+by the function that spinned off the threads after all the threads have
+finished.
+
address@hidden
address@hidden
address@hidden a barrier before re-using it:} It is very important to
+destroy the barrier before reusing it. This destroy function not only
+destroys the internal structures, it also waits (in 1 microsecond
+intervals, so you will not notice!) until all the threads don't need the
+barrier structure any more. Without destrying, if you immediately spin off
+new threads with the barrier, then the internal structure of the remaining
+threads will get mixed with the new ones and you will get extremely hard to
+debug errors.
address@hidden cartouche
address@hidden deftypefun
+
address@hidden Gnuastro's thread related functions,  , Implementation of 
pthread_barrier, Multithreaded programming
address@hidden Gnuastro's thread related functions
+
+These are some high-level functions in @file{gnuastro/threads.h} to
+facilitate programming in with POSIX threads. We have created a simple C
+program for testing these functions in @file{tests/lib/multithread.c}. This
+small program was compiled and run on your system when you ran
address@hidden check}. You can use it as a template to easily create small
+multithreaded programs and efficiently use your powerful CPU.
+
address@hidden Macro GAL_THREADS_NON_THRD_INDEX
+This value will be used in the output of @code{gal_threads_dist_in_threads}
+as a non-index. It plays the same role as a string's null character:
address@hidden': as soon as the parser sees this value, it will stop
+continuing.
address@hidden deffn
+
address@hidden void gal_threads_attr_barrier_init (pthread_attr_t @code{*attr}, 
pthread_barrier_t @code{*b}, size_t @code{limit})
address@hidden Detached threads
+Initialize the general thread attribute @code{attr} and the barrier
address@hidden with @code{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 @code{pthread_join} won't work on these threads. You have to use
+the barrier constructs to wait for all threads to finish.
address@hidden deftypefun
+
address@hidden void gal_threads_dist_in_threads (size_t @code{numactions}, 
size_t @code{numthreads}, size_t @code{**outthrds}, size_t @code{*outthrdcols})
+
+Identify the ``index''es (starting from 0) of the actions to be done on
+each thread in the @code{outthrds} array. @code{outthrds} is treated as a
+2D array with @code{numthreads} rows and @code{outthrdcols}. 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 @mymath{A} actions (where there is only one function
+and the input values differ for each action) and @mymath{T} threads
+available to the system with @mymath{A>T} (common values for these two
+would be @mymath{A>1000} and @mymath{T<10}). Spinning off a thread is not a
+cheap job and requires a significant number of CPU cycles. Therefore,
+creating @mymath{A} threads is not the best way to address such a
+problem. The most efficient way to manage the actions is such that only
address@hidden threads are created, and each thread works on a list of actions
+(internally) in series (at most @mymath{A/T}). This way your system spends
+the minimum time necessary to create and destroy threads while getting all
+the actions done.
+
+This function does this management for you: each row in the @code{outthrds}
+array contains the indexs of actions which must be done by one
+thread. @code{outthrds} contains @code{outthrdcols} columns. In using
address@hidden, you don't have to know the number of columns: you can
+check to see if the index is @code{GAL_THREADS_NON_THRD_INDEX}. Exactly the
+same as you would when checking if have finished parsing a string. Please
+see the example program in @file{tests/lib/multithread.c} for a
+demonstration.
+
address@hidden deftypefun
+
 
 
 
@@ -17120,7 +17316,6 @@ read along.
 @menu
 * Mandatory source code files::  How the source files of each program are 
managed.
 * Coding conventions::          Basic conventions for coding structure.
-* Multithreaded programming::   Gnuastro's multithreaded programming style.
 * Documentation::               Documentation is an integral part of Gnuastro.
 * The TEMPLATE utility::        A template to create new utilities.
 @end menu
@@ -17284,7 +17479,7 @@ programs with @option{--cite}, see @ref{Operating 
modes}.
 * Multithreaded programming::   Gnuastro uses POSIX threads.
 @end menu
 
address@hidden Coding conventions, Multithreaded programming, Mandatory source 
code files, Program source
address@hidden Coding conventions, Documentation, Mandatory source code files, 
Program source
 @subsection Coding conventions
 
 @cindex GNU coding standards
@@ -17564,45 +17759,9 @@ which contains nice animated images of using Emacs.
 @end cartouche
 
 
address@hidden Multithreaded programming, Documentation, Coding conventions, 
Program source
address@hidden Multithreaded programming
-
address@hidden Multithreaded programming
-Most of the programs in Gnuastro utilize multi-threaded programming
-for the CPU intensive processing steps. This can potentially lead to a
-significant decrease in the running time of a program, see @ref{A note
-on threads}. In terms of reading the code, you don't need to know
-anything about multi-threaded programming. You can simply follow the
-case where only one thread is to be used. In these cases, threads are
-not used and can be completely ignored.
-
address@hidden POSIX threads library
address@hidden Lawrence Livermore National Laboratory
-At the time K&R's book was written, using threads was not common. We
-use POSIX threads for multi-threaded programming, defined in the
address@hidden system wide header. There are various resources for
-learning to use POSIX threads, the excellent tutorial from Lawrence
-Livermore National
address@hidden@url{https://computing.llnl.gov/tutorials/pthreads/}}
-is a very good start.  The book `Advanced programming in the Unix
-environment'@footnote{Don't let the title scare you! The two chapters
-on Multi-threaded programming are very self sufficient and don't need
-any more knowledge than K&R.}, by Richard Stevens and Stephen Rago,
-Addison-Wesley, 2013 (Third edition) also has two chapters explaining
-the POSIX thread constructs which can be very helpful.
-
address@hidden OpenMP
-An alternative to POSIX threads was OpenMP, but POSIX threads are low
-level, allowing much more control, while being easier to understand,
-see @ref{Why C}. All the situations where threads are used are
-completely independent with minimal need of coordination between the
-threads.  Such problems are known as ``embarrassingly parallel''
-problems. They are some of the simplest problems to solve with threads
-and also the ones that benefit most from threads, see the LLNL
address@hidden@url{https://computing.llnl.gov/tutorials/parallel_comp/}}.
 
 
address@hidden Documentation, The TEMPLATE utility, Multithreaded programming, 
Program source
address@hidden Documentation, The TEMPLATE utility, Coding conventions, Program 
source
 @subsection Documentation
 
 Documentation (this book) is an integral part of Gnuastro.
@@ -18670,7 +18829,10 @@ exported structures and functions start with 
@code{gal_}. This abbreviation
 stands for @emph{G}NU @emph{A}stronomy @emph{L}ibrary. The next element in
 the name is the name of the header which declares or defines them, so to
 use the @code{gal_array_fset_const} function, you have to @code{#include
-<gnuastro/array.h>}. See @ref{Gnuastro library} for more.
+<gnuastro/array.h>}. See @ref{Gnuastro library} for more. The
address@hidden constructs are our implementation and are only
+available on systems that don't have them, see @ref{Implementation of
+pthread_barrier}.
 @printindex fn
 @unnumbered Index
 @printindex cp
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 8a8145d..761a4bb 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -70,7 +70,9 @@ CLEANFILES = gnuastro.pc gnuastro/gnuastro.h
 gnuastro/gnuastro.h: Makefile gnuastro.h.in
        rm -f $@ address@hidden
        $(MKDIR_P) gnuastro
-       $(SED) -e 's|@address@hidden|$(VERSION)|g' $(srcdir)/gnuastro.h.in >> 
address@hidden
+       $(SED) -e 's|@address@hidden|$(VERSION)|g'                          \
+              -e 's|@address@hidden|$(HAS_PTHREAD_BARRIER)|g'  \
+               $(srcdir)/gnuastro.h.in >> address@hidden
        chmod a-w address@hidden
        mv address@hidden $@
 
diff --git a/lib/gnuastro/threads.h b/lib/gnuastro/threads.h
index 0cb6432..e2bcfc7 100644
--- a/lib/gnuastro/threads.h
+++ b/lib/gnuastro/threads.h
@@ -27,7 +27,17 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
    must be included before the C++ preparations below */
 #include <pthread.h>
 
-
+/* When this header is included within Gnuastro's building process,
+   `IN_GNUASTRO_BUILD' is defined. In the build process, installation
+   information (in particular `GAL_GNUASTRO_PTHREAD_BARRIER' that we need
+   below) is kept in `config.h'. When building a user's programs, this
+   information is kept in `gnuastro/gnuastro.h'. Note that all `.c' files
+   must start with the inclusion of `config.h' and that
+   `gnuastro/gnuastro.h' is only created at installation time (not present
+   during the building of Gnuastro).*/
+#ifndef IN_GNUASTRO_BUILD
+#include <gnuastro/gnuastro.h>
+#endif
 
 /* C++ Preparations */
 #undef __BEGIN_C_DECLS
@@ -56,7 +66,7 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 /*****************************************************************/
 /*********    Implementation of pthread_barrier    ***************/
 /*****************************************************************/
-#ifndef HAVE_PTHREAD_BARRIER
+#if GAL_GNUASTRO_PTHREAD_BARRIER == 0
 
 /* Integer number of nano-seconds that `pthread_barrier_destroy' should
    wait for a check to see if all barriers have been reached. */
@@ -83,7 +93,7 @@ pthread_barrier_wait(pthread_barrier_t *b);
 int
 pthread_barrier_destroy(pthread_barrier_t *b);
 
-#endif
+#endif  /* GAL_GNUASTRO_PTHREAD_BARRIER == 0 */
 
 
 
@@ -91,12 +101,12 @@ pthread_barrier_destroy(pthread_barrier_t *b);
 /****************      gnuastro functions       ******************/
 /*****************************************************************/
 void
-gal_threads_dist_in_threads(size_t nindexs, size_t nthrds, size_t **outthrds,
-                            size_t *outthrdcols);
+gal_threads_dist_in_threads(size_t numactions, size_t numthreads,
+                            size_t **outthrds, size_t *outthrdcols);
 
 void
 gal_threads_attr_barrier_init(pthread_attr_t *attr, pthread_barrier_t *b,
-                              size_t numthreads);
+                              size_t limit);
 
 
 
diff --git a/lib/threads.c b/lib/threads.c
index 89ff98b..6abd339 100644
--- a/lib/threads.c
+++ b/lib/threads.c
@@ -42,7 +42,7 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 /* Re-implementation of the example code given in:
 http://blog.albertarmea.com/post/47089939939/using-pthread-barrier-on-mac-os-x
  */
-#ifndef HAVE_PTHREAD_BARRIER
+#if GAL_GNUASTRO_PTHREAD_BARRIER == 0
 
 /* Initialize the barrier structure. A barrier is a high-level way to wait
    until several threads have finished. */
@@ -143,7 +143,8 @@ pthread_barrier_destroy(pthread_barrier_t *b)
   pthread_mutex_destroy(&b->mutex);
   return 0;
 }
-#endif
+
+#endif  /* GAL_GNUASTRO_PTHREAD_BARRIER == 0 */
 
 
 
@@ -167,35 +168,35 @@ pthread_barrier_destroy(pthread_barrier_t *b)
 /*******************************************************************/
 /************     Distribute job indexs in threads    **************/
 /*******************************************************************/
-/* We have `nindexs` jobs and we want their indexs to be divided
-   between `nthrds` CPU threads. This function will give each index to
+/* We have `numactions` jobs and we want their indexs to be divided
+   between `numthreads` CPU threads. This function will give each index to
    a thread such that the maximum difference between the number of
    images for each thread is 1. The results will be saved in a 2D
    array of `outthrdcols` columns and each row will finish with a
    (size_t) -1, which is larger than any possible index!. */
 void
-gal_threads_dist_in_threads(size_t nindexs, size_t nthrds, size_t **outthrds,
-                            size_t *outthrdcols)
+gal_threads_dist_in_threads(size_t numactions, size_t numthreads,
+                            size_t **outthrds, size_t *outthrdcols)
 {
   size_t *sp, *fp;
   size_t i, *thrds, thrdcols;
-  *outthrdcols = thrdcols = nindexs/nthrds+2;
+  *outthrdcols = thrdcols = numactions/numthreads+2;
 
   errno=0;
-  thrds=*outthrds=malloc(nthrds*thrdcols*sizeof *thrds);
+  thrds=*outthrds=malloc(numthreads*thrdcols*sizeof *thrds);
   if(thrds==NULL)
     error(EXIT_FAILURE, errno, "allocating thrds in prepindexsinthreads");
 
   /* Initialize all the elements to NONINDEX. */
-  fp=(sp=thrds)+nthrds*thrdcols;
+  fp=(sp=thrds)+numthreads*thrdcols;
   do *sp=GAL_THREADS_NON_THRD_INDEX; while(++sp<fp);
 
   /* Distribute the labels in the threads.  */
-  for(i=0;i<nindexs;++i)
-    thrds[ (i%nthrds)*thrdcols+(i/nthrds) ] = i;
+  for(i=0;i<numactions;++i)
+    thrds[ (i%numthreads)*thrdcols+(i/numthreads) ] = i;
 
   /* In case you want to see the result:
-  for(i=0;i<nthrds;++i)
+  for(i=0;i<numthreads;++i)
     {
       size_t j;
       printf("\n\n############################\n");
@@ -214,7 +215,7 @@ gal_threads_dist_in_threads(size_t nindexs, size_t nthrds, 
size_t **outthrds,
 
 void
 gal_threads_attr_barrier_init(pthread_attr_t *attr, pthread_barrier_t *b,
-                              size_t numthreads)
+                              size_t limit)
 {
   int err;
 
@@ -222,6 +223,6 @@ gal_threads_attr_barrier_init(pthread_attr_t *attr, 
pthread_barrier_t *b,
   if(err) error(EXIT_FAILURE, 0, "thread attr not initialized");
   err=pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);
   if(err) error(EXIT_FAILURE, 0, "thread attr not detached");
-  err=pthread_barrier_init(b, NULL, numthreads);
+  err=pthread_barrier_init(b, NULL, limit);
   if(err) error(EXIT_FAILURE, 0, "thread barrier not initialized");
 }
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 180256a..2657dbe 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -56,9 +56,10 @@ export hasghostscript=$(MAYBE_HASGHOSTSCRIPT);
 
 # Compilations that are to be done with `make check'.
 LDADD = -lgnuastro
-check_PROGRAMS = versioncpp arraymanip
+check_PROGRAMS = versioncpp arraymanip multithread
 arraymanip_SOURCES = lib/arraymanip.c
 versioncpp_SOURCES = lib/versioncpp.cpp
+multithread_SOURCES = lib/multithread.c
 
 
 
diff --git a/tests/lib/multithread.c b/tests/lib/multithread.c
new file mode 100644
index 0000000..9c836d6
--- /dev/null
+++ b/tests/lib/multithread.c
@@ -0,0 +1,155 @@
+/*********************************************************************
+A test program to multithreaded building using Gnuastro's helpers.
+
+Original author:
+     Mohammad Akhlaghi <address@hidden>
+Contributing author(s):
+Copyright (C) 2016, Free Software Foundation, Inc.
+
+Gnuastro is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+
+Gnuastro is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Gnuastro. If not, see <http://www.gnu.org/licenses/>.
+**********************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "gnuastro/threads.h"
+
+
+/* The params structure will keep the input information for each thread. As
+   you see below, we will actually be defining an array of these
+   structures, one for each thread. The reason for this is that the
+   function that spins off threads only passes one argument, so as that
+   argument, we will be passing the pointer to this structure. You can
+   easily add new elements to this structure to use in the threads
+   function. */
+struct params
+{
+  size_t            id; /* Id of this thread.                            */
+  size_t       *indexs; /* Indexes of actions to be done in this thread. */
+  pthread_barrier_t *b; /* Pointer the barrier for all threads.          */
+};
+
+
+
+
+
+/* Worker function on threads */
+void *
+worker(void *inparam)
+{
+  /* The first thing to do is to say what the input pointer actually is. */
+  struct params *prm=(struct params*)inparam;
+
+  /* Now you can go onto do defining the function like any other
+     function: first you define the variables and so on... */
+  size_t i;
+
+  /* Go over the jobs indexed for this thread: */
+  for(i=0; prm->indexs[i] != GAL_THREADS_NON_THRD_INDEX; ++i)
+    {
+      /* The indexes of the actions will make it possible to point to
+         whatever data structure or input you want. So in this test, we
+         will just print the thread ID and action id. */
+      printf("thread %lu: %lu\n", prm->id, prm->indexs[i]);
+    }
+
+  /* Wait until all other threads finish. When there was only one thread,
+     we explicitly set the pointer to the barrier structure to NULL, so
+     only wait when a barrier is actually defined.*/
+  if(prm->b)
+    pthread_barrier_wait(prm->b);
+
+  /* Return the NULL pointer. */
+  return NULL;
+}
+
+
+
+
+/* This is the thread spinner function. */
+int
+main(void)
+{
+  int err;
+  pthread_t t;          /* All thread ids saved in this, not used. */
+  struct params *prm;
+  size_t numbarriers;
+  pthread_attr_t attr;
+  pthread_barrier_t b;
+  size_t i, *indexs, thrdcols;
+  size_t numthreads=8, numactions=1000;
+
+  /* Allocate the array of `param' structures. Note that in most cases, the
+     number of threads will not be a constant like this simple case, it
+     will be a variable passed to the thread-spinner. So we are using
+     dynamic allocation for more general use as a tutorial. */
+  prm=malloc(numthreads*sizeof *prm);
+  if(prm==NULL)
+    {
+      fprintf(stderr, "%lu bytes could not be allocated for prm.",
+              numthreads*sizeof *prm);
+      exit(EXIT_FAILURE);
+    }
+
+  /* Distribute the actions into the threads: */
+  gal_threads_dist_in_threads(numactions, numthreads, &indexs, &thrdcols);
+
+  /* Do the job: when only one thread is necessary, there is no need to
+     spin off one thread, just call the function directly (spinning off
+     threads is expensive). This is for the generic thread spinner
+     function, not this simple function where `numthreads' is a
+     constant. */
+  if(numthreads==1)
+    {
+      prm[0].id=0;
+      prm[0].b=NULL;
+      prm[0].indexs=indexs;
+      worker(&prm[0]);
+    }
+  else
+    {
+      /* Initialize the attributes. Note that this running thread
+         (that spinns off the nt threads) is also a thread, so the
+         number the barriers should be one more than the number of
+         threads spinned off. */
+      numbarriers = (numactions<numthreads ? numactions : numthreads) + 1;
+      gal_threads_attr_barrier_init(&attr, &b, numbarriers);
+
+      /* Spin off the threads: */
+      for(i=0;i<numthreads;++i)
+        if(indexs[i*thrdcols]!=GAL_THREADS_NON_THRD_INDEX)
+          {
+            prm[i].id=i;
+            prm[i].b=&b;
+            prm[i].indexs=&indexs[i*thrdcols];
+            err=pthread_create(&t, &attr, worker, &prm[i]);
+            if(err)
+              {
+                fprintf(stderr, "can't create thread %lu", i);
+                exit(EXIT_FAILURE);
+              }
+          }
+
+      /* Wait for all threads to finish and free the spaces. */
+      pthread_barrier_wait(&b);
+      pthread_attr_destroy(&attr);
+      pthread_barrier_destroy(&b);
+    }
+
+  /* Clean up. */
+  free(prm);
+  free(indexs);
+
+  /* Return. */
+  return EXIT_SUCCESS;
+}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]