Helios++
Helios software for LiDAR simulations
ThreadPool.h
1 #pragma once
2 
3 #include <boost/asio.hpp>
4 #include <boost/thread.hpp>
5 #include <boost/function.hpp>
6 #include <noise/RandomnessGenerator.h>
7 #include <UniformNoiseSource.h>
8 #include <logging.hpp>
9 #include <sstream>
10 
15 private:
16  // *** ATTRIBUTES *** //
17  // ******************** //
22  boost::asio::io_service io_service_;
28  boost::asio::io_service::work work_;
32  std::size_t pool_size;
36  boost::thread_group threads_;
41  std::size_t available_;
45  boost::mutex mutex_;
50  boost::condition_variable cond_;
51 
56  std::vector<std::vector<double>> *apMatrices;
57 
66  RandomnessGenerator<double> *randGens2; // To substitute BoxMuller
71 
79 
80 public:
81  // *** CONSTRUCTION / DESTRUCTION *** //
82  // ************************************ //
89  explicit thread_pool(std::size_t _pool_size, double deviceAccuracy)
90  : work_(io_service_),
91  pool_size(_pool_size),
92  available_(_pool_size)
93  {
94  apMatrices = new std::vector<std::vector<double>>[pool_size];
95  randGens = new RandomnessGenerator<double>[pool_size];
96  randGens2 = new RandomnessGenerator<double>[pool_size];
97  intersectionHandlingNoiseSources =
99  resourceSetAvailable = new bool[pool_size];
100 
101 
102  for (std::size_t i = 0; i < pool_size; ++i)
103  {
104  resourceSetAvailable[i] = true;
105  randGens[i] = *DEFAULT_RG;
106  randGens[i].computeUniformRealDistribution(0.0, 1.0);
107  randGens[i].computeNormalDistribution(0.0, deviceAccuracy);
108  randGens2[i] = *DEFAULT_RG;
109  randGens2[i].computeNormalDistribution(0.0, 1.0);
110  intersectionHandlingNoiseSources[i] = UniformNoiseSource<double>(
111  *DEFAULT_RG, 0.0, 1.0
112  );
113  threads_.create_thread(boost::bind(
114  &boost::asio::io_service::run,
115  &io_service_
116  ));
117  }
118  }
119 
120  ~thread_pool(){
121  // Force all threads to return from io_service::run().
122  io_service_.stop();
123 
124  // Suppress all exceptions.
125  try
126  {
127  threads_.join_all();
128  }
129  catch (const std::exception&) {}
130 
131  delete[] apMatrices;
132  delete[] randGens;
133  delete[] randGens2;
134  delete[] resourceSetAvailable;
136  }
137 
138 private:
139  // *** M E T H O D S *** //
140  // *********************** //
152  for(size_t i = 0 ; i < pool_size ; i++){
153  if(resourceSetAvailable[i]) return i;
154  }
155  return -1;
156  }
157 
158 
159 public:
165  std::size_t getPoolSize(){return pool_size;}
166 
167 
171  template < typename Task > void run_task(Task task){
172  boost::unique_lock< boost::mutex > lock(mutex_);
173 
174  // If no threads are available, then wait for a thread to finish.
175  if (0 == available_){
176  cond_.wait(lock);
177  }
178 
179  // Decrement count, indicating thread is no longer available.
180  --available_;
181 
182  // Get resource set index
183  int resourceIdx = getAvailableResourceSetIndex();
184  resourceSetAvailable[resourceIdx] = false;
185 
186  // Post a wrapped task into the queue.
187  io_service_.post(
188  boost::bind(
190  this,
191  boost::function<
192  void(
193  std::vector<std::vector<double>>&,
197  )
198  >(task),
199  resourceIdx
200  )
201  );
202  }
203 
207  void join(){
208  boost::unique_lock<boost::mutex> lock(mutex_);
209  while(available_ < pool_size){
210  cond_.wait(lock);
211  }
212  }
213 
214 private:
223  void wrap_task(
224  boost::function<void(
225  std::vector<std::vector<double>>&,
229  )> &task,
230  int resourceIdx
231  ){
232  // Run the user supplied task.
233  try
234  {
235  task(
236  apMatrices[resourceIdx],
237  randGens[resourceIdx],
238  randGens2[resourceIdx],
239  intersectionHandlingNoiseSources[resourceIdx]
240  );
241  }
242  // Suppress all exceptions.
243  catch (const std::exception &e) {
244  std::stringstream ss;
245  ss << "thread_pool::wrap_task EXCEPTION: " << e.what();
246  logging::WARN(ss.str());
247  }
248 
249  // Task has finished, so increment count of available threads.
250  boost::unique_lock< boost::mutex > lock(mutex_);
251  ++available_;
252  resourceSetAvailable[resourceIdx] = true;
253  cond_.notify_one();
254  }
255 };
std::size_t getPoolSize()
Obtain the thread pool size.
Definition: ThreadPool.h:165
RandomnessGenerator< double > * randGens2
Second randomness generators (to substitute old box muller), one per thread.
Definition: ThreadPool.h:66
void wrap_task(boost::function< void(std::vector< std::vector< double >> &, RandomnessGenerator< double > &, RandomnessGenerator< double > &, NoiseSource< double > &)> &task, int resourceIdx)
Wrap a task so that available threads count can be increased once provided task has been completed...
Definition: ThreadPool.h:223
boost::condition_variable cond_
Condition var to handle tasks dispatching depending on available threads.
Definition: ThreadPool.h:50
boost::mutex mutex_
Mutex to handle concurrent tasks.
Definition: ThreadPool.h:45
Class representing a thread pool to deal with multi threading tasks.
Definition: ThreadPool.h:14
void join()
Lock until all pending threads have finished.
Definition: ThreadPool.h:207
UniformNoiseSource< double > * intersectionHandlingNoiseSources
Intersection handling noise sources, one per thread.
Definition: ThreadPool.h:70
boost::asio::io_service io_service_
Instance of boost input/output service for asynchronous data processing.
Definition: ThreadPool.h:22
int getAvailableResourceSetIndex()
Obtain the index of an available resource set.
Definition: ThreadPool.h:151
RandomnessGenerator< double > * randGens
First randomness generators (general purpose), one per thread.
Definition: ThreadPool.h:61
std::size_t pool_size
Size of thread pool (number of threads)
Definition: ThreadPool.h:32
std::size_t available_
Number of available threads, those which are not currently performing a task.
Definition: ThreadPool.h:41
bool * resourceSetAvailable
Array of flags specifying availability of resource sets.
Definition: ThreadPool.h:78
void run_task(Task task)
Run a task when there is an available thread for it.
Definition: ThreadPool.h:171
boost::thread_group threads_
Group of threads.
Definition: ThreadPool.h:36
boost::asio::io_service::work work_
Instance of work to report the io service when it has pending tasks.
Definition: ThreadPool.h:28
void computeNormalDistribution(RealType mean, RealType stdev)
Compute a normal distribution using the specified real data type.
Definition: RandomnessGenerator.h:380
std::vector< std::vector< double > > * apMatrices
Definition: ThreadPool.h:56
void computeUniformRealDistribution(RealType lowerBound, RealType upperBound)
Compute a uniform real distribution using the specified real data type.
Definition: RandomnessGenerator.h:343
thread_pool(std::size_t _pool_size, double deviceAccuracy)
Thread pool constructor.
Definition: ThreadPool.h:89