Management of a pool of threads to run tasks in pipeline. More...
#include <PipeLine.hpp>
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. | |
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(); }
| sal3d::PipeLine< Task >::PipeLine | ( | int | nthreads ) | [inline] |
| 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.
| int sal3d::PipeLine< Task >::nthreads | ( | ) | const [inline] |
Return the number of threads in the pool.
| 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.
| 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.
| 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.
1.7.2