Public Member Functions

sal3d::PipeLine< Task > Class Template Reference
[Acquire]

Management of a pool of threads to run tasks in pipeline. More...

#include <PipeLine.hpp>

List of all members.

Public Member Functions

 PipeLine (int nthreads)
 Start a PipeLine thread pool with the given number of threads.
 ~PipeLine ()
 Destroy the thread pool, deleting its related threads.
void post (const Task &t)
 Give the task to one free thread to run it.
void wait ()
 Wait for all the tasks given to threads to finish.
bool wait (int timeout_ms)
 Wait with timeout for all the tasks given to threads to finish.
int nthreads () const
 Return the number of threads in the pool.

Detailed Description

template<typename Task>
class sal3d::PipeLine< Task >

Management of a pool of threads to run tasks in pipeline.

This class requires linking with acquire.lib (import library for acquire.dll).

At the PipeLine creation, the given number of threads will be spawned ready to execute the tasks. The PipeLine object allows queuing tasks, which will be run by any free thread in the pool, maintaining the threads busy as much as possible.

The tasks are queued through the post() method, and it is possible to wait until all the queued tasks have been run using the wait() method.

The task objects passed to post() should be copiable. For each task queued, the threads will call two member functions of a heap copy of the task: Task::parallel() and Task::sequential(). The Task::parallel() function of different tasks may be called in any order, regardless of the enqueing order - this function should do the heavy job in order to take advantage of Symmetric Multi-Processing like in multicore computers. The Task::sequential() function of different tasks is guaranteed to be called in the enqueuing order, after having called the Task::parallel() function, and only after the Task::sequential() call of the previous queued task has finished. If your tasks don't require any order of execution, please consider the simpler ThreadPool class.

PipeLine objects cannot be copied, in order to maintain a single entry point for task queuing and waiting, for any given PipeLine.

Example of usage, where the user has a function to calculate the volume of cheese being scanned, and cut it at proper positions, taking profit of four threads in a four core machine:

 void
 sliceCheese(sal3d::FrameGrabber &fg, float maxvolume)
 {
     class pftask
     {
         public:
             pftask(const sal3d::Frame &f,
                 const sal3d::PeakFinder &pf,
                 double &volume, float maxvolume):
                 _frame(f), _peakfinder(pf),
                 _volume_accum(volume),
                 _maxvolume(maxvolume)
             {
             }

             void parallel()
             {
                 // We make a temporary rangemap of a single profile,
                 // to allocate the profile for the peakfinder call.
                 sal3d::RangeMap rm(f.height(), 1);
                 sal3d::Profile p(rm.getNewProfile());
                 // First heavy task
                 _peakfinder(_frame, p);
                 // Second heavy task
                 _volume = calculateSliceVolume(p);
             }

             void sequential()
             {
                 // This call is assured by PipeLine to be serialized in
                 // proper order according to the post order, so
                 // we can modify the shared variable _volume_accum
                 // without harm.
                 _volume_accum += _volume;
                 if (_volume_accum > _maxvolume)
                 {
                     cutCheese();
                     _volume_accum = 0;
                 }
             }

         private:
             const sal3d::Frame _frame;
             const sal3d::PeakFinder &_peakfinder;
             double &_volume_accum;
             const double _maxvolume;
             double _volume;
     };

     PipeLine<pftask> pool(4); // Four threads
     sal3d::PeakFinder pf(100 /* threshold */);
 
     double volume = 0.;
     while(ShouldKeepSlicing())
     {
         sal3d::Frame f(fg.frame());
         pftask task(f, pf, volume, 10000.);
         pool.post(task);
     }
     pool.wait();
 }

Constructor & Destructor Documentation

template<typename Task >
sal3d::PipeLine< Task >::PipeLine ( int  nthreads ) [inline]

Start a PipeLine thread pool with the given number of threads.

This will spawn as threads as the user requested, and they will wait for tasks to be done. These threads will last until the PipeLine object is destroyed.

template<typename Task >
sal3d::PipeLine< Task >::~PipeLine (  ) [inline]

Destroy the thread pool, deleting its related threads.

This will wait for all the thread tasks to be finished, and then it will destroy the threads managed by this object.


Member Function Documentation

template<typename Task >
int sal3d::PipeLine< Task >::nthreads (  ) const [inline]

Return the number of threads in the pool.

Returns:
The number of threads in the pool, set at constructor time
template<typename Task >
void sal3d::PipeLine< Task >::post ( const Task &  t ) [inline]

Give the task to one free thread to run it.

This method will block until there one thread free in the pool, and then it will give a copy of the task object passed to that thread. The thread will call the Task::parallel() method of the given task object copy, and then Task::sequential(), where the sequential methods for multiple tasks are called in order and serialized. This method will return once the task is given to the thread, regardless of the time when the task finishes.

template<typename Task >
bool sal3d::PipeLine< Task >::wait ( int  timeout_ms ) [inline]

Wait with timeout for all the tasks given to threads to finish.

Block until all the tasks ever given to the threads in this ThreadPool are finished, or until the timeout finishes.

Returns:
true when all tasks finished before the timeout, false otherwise
template<typename Task >
void sal3d::PipeLine< Task >::wait (  ) [inline]

Wait for all the tasks given to threads to finish.

Block until all the tasks ever given to the threads in this thread pool are finished.


The documentation for this class was generated from the following file: