[vspline] 31/72: added coordinate.h

Kay F. Jahnke kfj-guest at moszumanska.debian.org
Sun Jul 2 09:02:40 UTC 2017


This is an automated email from the git hooks/post-receive script.

kfj-guest pushed a commit to branch master
in repository vspline.

commit f738e1a7c5d196f1b572df4da66b1ce75487296b
Author: Kay F. Jahnke <kfjahnke at gmail.com>
Date:   Wed Feb 1 10:44:49 2017 +0100

    added coordinate.h
---
 coordinate.h   | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 interpolator.h |  17 +++---
 multithread.h  | 162 +++++++++++++++++++++-----------------------------------
 remap.h        |   4 +-
 thread_pool.h  |  27 +++++-----
 5 files changed, 252 insertions(+), 121 deletions(-)

diff --git a/coordinate.h b/coordinate.h
new file mode 100644
index 0000000..6093636
--- /dev/null
+++ b/coordinate.h
@@ -0,0 +1,163 @@
+/************************************************************************/
+/*                                                                      */
+/*    vspline - a set of generic tools for creation and evaluation      */
+/*              of uniform b-splines                                    */
+/*                                                                      */
+/*            Copyright 2015, 2016 by Kay F. Jahnke                     */
+/*                                                                      */
+/*    Permission is hereby granted, free of charge, to any person       */
+/*    obtaining a copy of this software and associated documentation    */
+/*    files (the "Software"), to deal in the Software without           */
+/*    restriction, including without limitation the rights to use,      */
+/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
+/*    sell copies of the Software, and to permit persons to whom the    */
+/*    Software is furnished to do so, subject to the following          */
+/*    conditions:                                                       */
+/*                                                                      */
+/*    The above copyright notice and this permission notice shall be    */
+/*    included in all copies or substantial portions of the             */
+/*    Software.                                                         */
+/*                                                                      */
+/*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
+/*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
+/*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
+/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
+/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
+/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
+/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
+/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
+/*                                                                      */
+/************************************************************************/
+
+/*! \file coordinate.h
+
+    \brief a traits class for coordinates
+
+    Throughout the evaluation part of vspline, we deal with coordinates.
+    In the context of b-spline evaluation we have to handle coordinate
+    types beyond simple TinyVectors of some type: we also deal with
+    'split' types, coordinates split into integral part and remainder.
+    Additionally, there is 'compact_split_type' consisting of an offset
+    and an nD fractional part.
+    To handle these types their components consistently, we define a
+    traits class 'coordinate_traits'.
+*/
+
+#ifndef VSPLINE_COORDINATE_H
+#define VSPLINE_COORDINATE_H
+
+#include <vigra/tinyvector.hxx>
+
+namespace vspline {
+
+/// first we fix 'unsplit' nD coordinate types as vigra TinyVectors
+
+template < int dimension ,
+           typename ic_type >
+using nd_ic_type = vigra::TinyVector < ic_type , dimension > ;
+
+template < int dimension ,
+           typename rc_type >
+using nd_rc_type = vigra::TinyVector < rc_type , dimension > ;
+
+/// We start out with the definition of split coordinates:
+/// class split_type contains n-dimensional 'split coordinates', consisting of the
+/// integral and fracional part of the 'original' real coordinates, separated so that
+/// they can be processed by the evaluation routine.
+
+template < int _dimension ,
+           typename _ic_type ,
+           typename _rc_type >
+struct split_type
+{
+  typedef _ic_type ic_type ;
+  typedef _rc_type rc_type ;
+  enum { dimension = _dimension } ;
+
+  typedef vigra::TinyVector < ic_type , dimension > nd_ic_type ;
+  typedef vigra::TinyVector < rc_type , dimension > nd_rc_type ;
+
+  nd_ic_type select ; ///< named select because it selects a specific location
+  nd_rc_type tune ;   ///< named tune because it provides additional 'fine-tuning'
+} ;
+
+/// compact_split_type is similar to split_type but instead of the nD integral
+/// coordinate it has a single offset in 'select' which contains the same information
+/// in 'compacted' form: it's the sum of all individual components of select, multiplied
+/// with the strides of the container select indexes. 
+
+template < int _dimension ,
+           typename _ic_type ,
+           typename _rc_type >
+struct compact_split_type
+{
+  typedef _ic_type ic_type ;
+  typedef _rc_type rc_type ;
+  enum { dimension = _dimension } ;
+
+  typedef vigra::TinyVector < rc_type , dimension > nd_rc_type ;
+
+  ic_type select ;
+  nd_rc_type tune ;
+} ;
+
+/// now for the traits class. we want it to provide the following types:
+/// ic_type, rc_type, nd_ic_type and nd_rc_type. We also want an enum 'dimension'
+/// giving the dimesnion of the coordinate.
+
+template < class coordinate_type >
+struct coordinate_traits
+{
+  typedef coordinate_type rc_type ;
+  typedef int ic_type ;
+  enum { dimension = 1 } ;
+
+  typedef vigra::TinyVector < rc_type , dimension > nd_rc_type ;
+  typedef vigra::TinyVector < ic_type , dimension > nd_ic_type ;
+} ;
+
+/// here we have a partial specialization of class coordinate_traits for coordinates
+/// coming as vigra TinyVectors, which is used throughout for nD coordinates. Here we
+/// pick the TinyVector's value_type as our rc_type
+
+template < typename _rc_type , int _dimension >
+struct coordinate_traits < vigra::TinyVector < _rc_type , _dimension > >
+{
+  enum { dimension = _dimension } ;
+  typedef _rc_type rc_type ;
+  typedef int ic_type ;
+
+  typedef vigra::TinyVector < rc_type , dimension > nd_rc_type ;
+  typedef vigra::TinyVector < ic_type , dimension > nd_ic_type ;
+} ;
+
+/// since remap can also operate with pre-split coordinates, we need another partial
+/// specialization of coordinate_traits for split_type, which also defines a value_type
+
+template < typename _rc_type , typename _ic_type , int _dimension >
+struct coordinate_traits < split_type < _dimension , _ic_type , _rc_type > >
+{
+  enum { dimension = _dimension } ;
+  typedef _rc_type rc_type ;
+  typedef _ic_type ic_type ;
+
+  typedef vigra::TinyVector < rc_type , dimension > nd_rc_type ;
+  typedef vigra::TinyVector < ic_type , dimension > nd_ic_type ;
+} ;
+
+/// the same for compact_split_type
+
+template < typename _rc_type , typename _ic_type , int _dimension >
+struct coordinate_traits < compact_split_type < _dimension , _ic_type , _rc_type > >
+{
+  enum { dimension = _dimension } ;
+  typedef _rc_type rc_type ;
+  typedef _ic_type ic_type ;
+
+  typedef vigra::TinyVector < rc_type , dimension > nd_rc_type ;
+  typedef vigra::TinyVector < ic_type , dimension > nd_ic_type ;
+} ;
+
+} ; // end of namespace vspline
+
+#endif // VSPLINE_COORDINATE_H
diff --git a/interpolator.h b/interpolator.h
index e7f120c..513043b 100644
--- a/interpolator.h
+++ b/interpolator.h
@@ -54,10 +54,13 @@
 
 namespace vspline {
 
-template < int _dimension ,    ///< dimension of the spline
-           class _value_type , ///< type of interpolation result
-           class _rc_type ,    ///< singular real coordinate, like float or double
-           class _ic_type >    ///< singular integral coordinate, like int
+template < int _dimension ,    // dimension of the spline
+           class _value_type , // type of interpolation result
+           class _rc_type ,    // singular real coordinate, like float or double
+           class _ic_type ,    // singular integral coordinate, like int
+           int _vsize = vspline::vector_traits
+                       < typename vigra::ExpandElementResult < _value_type > :: type >
+                       :: vsize>       
 struct interpolator
 {
   // fix the types we're dealing with
@@ -65,6 +68,8 @@ struct interpolator
   typedef _rc_type rc_type ;
 
   enum { dimension = _dimension } ;
+  enum { vsize = _vsize } ;
+
   typedef vigra::TinyVector < rc_type , dimension > nd_rc_type ;
   typedef vigra::TinyVector < ic_type , dimension > nd_ic_type ;
   
@@ -90,11 +95,11 @@ struct interpolator
   /// which is used for coefficients and results. this is fixed via
   /// the traits class vector_traits (in common.h)
   
-  typedef typename vector_traits < ele_type > :: type ele_v ;
+  typedef typename vector_traits < ele_type , vsize > :: type ele_v ;
   
   /// element count of Simd data types.
   
-  enum { vsize = ele_v::Size } ;
+//   enum { vsize = ele_v::Size } ;
 
   /// compatible-sized simdized type of vsize ic_type
 
diff --git a/multithread.h b/multithread.h
index 6b8b55c..9717d71 100644
--- a/multithread.h
+++ b/multithread.h
@@ -295,98 +295,38 @@ partition ( shape_range_type<d> range , int nparts )
   return shape_splitter < d > :: part ( range[1] , nparts ) ;
 }
 
-// forward declaration of struct joint_task and function action_wrapper()
-
-struct joint_task ;
-
-void action_wrapper ( std::function < void() > action , joint_task * p_coordinator ) ;
-
-/// struct joint_task serves as a coordinator of a multithreaded operation.
-/// on creation, it receives a vector of tasks, which are packaged as
-/// std::function<void()>. These tasks will usually be closures, produced by
-/// std::bind or equivalent techniques.
-///
-/// These tasks are wrapped in 'action_wrapper', which executes the task and
-/// communicates with the joint_task object to keep it updated on the progress
-/// of the tasks. Once the last task is complete, the joint_task in turn notifies
-/// the calling code.
-
-struct joint_task
-{
-  const int crew ;   // number of partial jobs to perform
-  int done ;         // number of partial jobs already completed
-  
-  std::mutex finished_mutex ; // to guard 'finished'
-  bool finished ;             // is set to true as predicate to test by caller
-  std::condition_variable finished_cv ; // the caller waits for this cv  
-  thread_pool & tp  ;
-  
-  joint_task ( thread_pool & _tp ,
-               std::vector < std::function < void() > > & taskv )
-  : tp (_tp ) ,
-    crew ( taskv.size() ) , // number of tasks
-    done ( 0 ) ,            // number of done tasks
-    finished ( false )      // not yet finished with all tasks
-  {
-    {
-      // under task_mutex, fill tasks into task queue
-      std::lock_guard<std::mutex> lk ( tp.task_mutex ) ;
-      for ( int i = 0 ; i < crew ; i++ )
-      {
-        // bind both the ith task and a pointer to this object to action_wrapper,
-        // resulting in a functional which is then pushed to the task queue
-        std::function < void() >
-          action = std::bind ( action_wrapper , taskv[i] , this ) ;
-        tp.task_queue.push ( action ) ;
-      }
-    }
-    tp.task_cv.notify_all() ; // alert all worker threads
-    {
-      // now wait for the last task to complete
-      std::unique_lock<std::mutex> lk ( tp.task_mutex ) ;
-      // the predicate done==crew rejects spurious wakes
-      tp.task_cv.wait ( lk , [&] { return done == crew ; } ) ;
-    }
-    // we're sure now that all tasks are done, so we let the caller know,
-    // who is waiting on finished_cv.
-    std::lock_guard<std::mutex> lk ( finished_mutex ) ;
-    finished = true ;
-    finished_cv.notify_one() ;
-  } ;
-} ;
-
 /// action_wrapper wraps a functional into an outer function which
-/// first calls the functional and then interacts with a joint_task
-/// object, increasing the joint_task object's 'done' count and checking
-/// if the increased done count is now equal to the total number of tasks
-/// the joint_task object coordinates. If that is so, the joint_task
-/// object is notified.
-
-void action_wrapper ( std::function < void() > action ,
-                      joint_task * p_coordinator )
+/// first calls the functional and then checks if this was the last
+/// of a bunch of actions to complete, by incrementing the counter
+/// p_done points to and comparing the result to 'nparts'. If the
+/// test succeeds, the caller is notified via the condition variable
+/// p_pool_cv points to, under the mutex p_pool_mutex points to.
+
+void action_wrapper ( std::function < void() > payload ,
+                      int nparts ,
+                      std::mutex * p_pool_mutex ,
+                      std::condition_variable * p_pool_cv ,
+                      int * p_done )
 {
-  // perform the wrapped action (the 'payload' initially passed to
-  // the joint task object in the 'taskv' argument)
+  // execute the 'payload'
 
-  action() ;
+  payload() ;
 
-  // under the coordinator's task_mutex, increase the coordinator's
-  // 'done' counter and test if it's now equal to 'crew', the total
-  // number of actions originating from p_coordinator
+  // under the coordinator's task_mutex, increase the caller's
+  // 'done' counter and test if it's now equal to 'nparts', the total
+  // number of actions in this bunch
   
   // TODO initially I had the notify_all call after closing the scope of
   // the lock guard, but I had random crashes. Changing the code to call
   // notify_all with the lock guard still in effect seemed to remove the
   // problem, but made me unsure of my logic.
   
-  // TODO might use a different condition variable for this purpose
-
-  std::lock_guard<std::mutex> lk ( p_coordinator->tp.task_mutex ) ;
-  if ( ++ (p_coordinator->done) == p_coordinator->crew ) ;
+  std::lock_guard<std::mutex> lk ( * p_pool_mutex ) ;
+  if ( ++ ( * p_done ) == nparts ) ;
   {
     // this was the last action originating from p_coordinator
     // notify the coordinator that the joint task is now complete
-    p_coordinator->tp.task_cv.notify_all() ;
+    p_pool_cv->notify_one() ;
   }
 }
 
@@ -397,15 +337,14 @@ void action_wrapper ( std::function < void() > action ,
 /// function used for all individual tasks), a partitioning, which contains
 /// information on which part of the data each task should process, and
 /// a set of additional parameters to pass on to the functor.
-/// The individual tasks are created by binding the functor with
+/// The individual 'payload' tasks are created by binding the functor with
 ///
 /// - a range from the partitioning, describing it's share of the data
 ///
 /// - the remaining parameters
 ///
-/// These tasks are stored in a std::vector 'taskv' which is used to
-/// create a 'joint_task' object which handles the interaction with the
-/// thread pool and notifies once all tasks have completed.
+/// These tasks are bound to a wrapper routine which takes care of
+/// signalling when the last task has completed.
 
 static thread_pool common_thread_pool ; // keep a thread pool only for multithread()
 
@@ -426,31 +365,52 @@ int multithread ( void (*pfunc) ( range_type , Types... ) ,
     return 1 ;
   }
 
-  // set up the individual tasks by binding all arguments to p_func,
-  // resulting in a vecor of std::function<void()> to pass to the
-  // joint_task object
+  int done = 0 ;                    // number of completed tasks
+  std::mutex pool_mutex ;           // mutex to guard access to done and pool_cv
+  std::condition_variable pool_cv ; // for signalling completion
+  
+  {
+    // under the thread pool's task_mutex, fill tasks into task queue
+    std::lock_guard<std::mutex> lk ( common_thread_pool.task_mutex ) ;
+    for ( int i = 0 ; i < nparts ; i++ )
+    {
+      // first create the 'payload' function
+      
+      std::function < void() > payload
+        = std::bind ( pfunc , partitioning[i] , args... ) ;
 
-  std::vector < std::function < void() > > taskv ( nparts ) ;
+      // now bind it to the action wrapper and enqueue it
 
-  for ( int s = 0 ; s < nparts ; s++ )
+      std::function < void() > action
+        = std::bind ( action_wrapper ,
+                      payload ,
+                      nparts ,
+                      &pool_mutex ,
+                      &pool_cv ,
+                      &done
+                    ) ;
 
-    taskv[s] = std::bind ( pfunc , partitioning[s] , args... ) ;
+      common_thread_pool.task_queue.push ( action ) ;
+    }
+  }
 
-  // create the joint_task object, passing the thread pool and
-  // the vector of tasks.
-  // The joint_task object launches the tasks and makes sure they
-  // all complete before notifying on its' finished_cv condition
-  // variable
+  // alert all worker threads
+   
+  common_thread_pool.task_cv.notify_all() ;
 
-  joint_task jt ( common_thread_pool , taskv ) ;
-  
-  // wait until 'jt.finished' is true
+  {
+    // now wait for the last task to complete. This is signalled by
+    // action_wrapper by notfying on pool_cv and doublechecked
+    // by testing for done == nparts
 
-  std::unique_lock<std::mutex> lk ( jt.finished_mutex ) ;
+    std::unique_lock<std::mutex> lk ( pool_mutex ) ;
+    
+    // the predicate done==crew rejects spurious wakes
+    
+    pool_cv.wait ( lk , [&] { return done == nparts ; } ) ;
+  }
   
-  jt.finished_cv.wait ( lk , [&jt] { return jt.finished ; } ) ;
-
-  // now the joint task is complete
+  // all jobs are done
 
   return nparts ;
 }
diff --git a/remap.h b/remap.h
index 47233d6..55fc9da 100644
--- a/remap.h
+++ b/remap.h
@@ -877,8 +877,8 @@ struct transform_generator
   
 #ifdef USE_VC
 
-  typedef typename vigra::ExpandElementResult < value_type > :: type ele_type ;
-  enum { vsize = vector_traits < ele_type > :: vsize } ;
+//   typedef typename vigra::ExpandElementResult < value_type > :: type ele_type ;
+  enum { vsize = interpolator_type :: vsize } ;
 
 #else
   
diff --git a/thread_pool.h b/thread_pool.h
index d65abef..bf03f93 100644
--- a/thread_pool.h
+++ b/thread_pool.h
@@ -54,23 +54,25 @@ namespace vspline
   
 class thread_pool
 {
-  // used to switch off the worker threads at program termination
+  // used to switch off the worker threads at program termination.
+  // access under task_mutex.
 
   bool stay_alive = true ;
 
-  /// the thread pool itself is held in this variable
+  // the thread pool itself is held in this variable. The pool
+  // does not change after construction
 
   std::vector < std::thread * > pool ;
   
 public:
 
-  // mutex and condition variable
-  // for interaction with the thread pool
+  // mutex and condition variable for interaction with the task queue
+  // and stay_alive
 
   std::mutex task_mutex ;
   std::condition_variable task_cv ;
   
-  // queue to hold tasks
+  // queue to hold tasks. access under task_mutex
 
   std::queue < std::function < void() > > task_queue ;
 
@@ -129,17 +131,18 @@ public:
     
   ~thread_pool()
   {
-    // under task_mutex, set stay_alive to false
-    
-    std::unique_lock<std::mutex> task_lock ( task_mutex ) ;
-    stay_alive = false ;
-    task_lock.unlock() ;
-    
+    {
+      // under task_mutex, set stay_alive to false
+      
+      std::lock_guard<std::mutex> task_lock ( task_mutex ) ;
+      stay_alive = false ;      
+    }
+
     // wake all inactive worker threads,
     // join all worker threads once they are finished
 
     task_cv.notify_all() ;
-
+    
     for ( auto threadp : pool )
     {
       threadp->join() ;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/vspline.git



More information about the debian-science-commits mailing list