[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