libDwm-0.6.0
DwmLoadBalancer.hh
Go to the documentation of this file.
1 //===========================================================================
2 // @(#) $DwmPath: dwm/libDwm/tags/libDwm-0.6.0/include/DwmLoadBalancer.hh 8401 $
3 // @(#) $Id: DwmLoadBalancer.hh 8401 2016-04-17 06:44:31Z dwm $
4 //===========================================================================
5 // Copyright (c) Daniel W. McRobb 2008, 2009, 2016
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 //
12 // 1. Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // 2. Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 // 3. The names of the authors and copyright holders may not be used to
18 // endorse or promote products derived from this software without
19 // specific prior written permission.
20 //
21 // IN NO EVENT SHALL DANIEL W. MCROBB BE LIABLE TO ANY PARTY FOR
22 // DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
23 // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE,
24 // EVEN IF DANIEL W. MCROBB HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
25 // DAMAGE.
26 //
27 // THE SOFTWARE PROVIDED HEREIN IS ON AN "AS IS" BASIS, AND
28 // DANIEL W. MCROBB HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
29 // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. DANIEL W. MCROBB MAKES NO
30 // REPRESENTATIONS AND EXTENDS NO WARRANTIES OF ANY KIND, EITHER
31 // IMPLIED OR EXPRESS, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 // WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE,
33 // OR THAT THE USE OF THIS SOFTWARE WILL NOT INFRINGE ANY PATENT,
34 // TRADEMARK OR OTHER RIGHTS.
35 //===========================================================================
36 
37 //---------------------------------------------------------------------------
40 //---------------------------------------------------------------------------
41 
42 #ifndef _DWMLOADBALANCER_HH_
43 #define _DWMLOADBALANCER_HH_
44 
45 extern "C" {
46  #include <unistd.h>
47 }
48 
49 #include <algorithm>
50 #include <iostream>
51 #include <queue>
52 #include <string>
53 #include <thread>
54 #include <vector>
55 
56 #include "DwmSysLogger.hh"
57 #include "DwmThreadQueue.hh"
58 
59 namespace Dwm {
60 
61  //--------------------------------------------------------------------------
78  //--------------------------------------------------------------------------
79  template <typename ItemT>
81  {
82  public:
83  //------------------------------------------------------------------------
85  //------------------------------------------------------------------------
86  class Worker
87  {
88  public:
89  //----------------------------------------------------------------------
93  //----------------------------------------------------------------------
94  Worker(uint32_t waitNotEmptyMicroseconds = 1000)
95  : _workQueue(), _keepRunning(false), _thread(),
96  _waitUsecs(waitNotEmptyMicroseconds)
97  {}
98 
99  //----------------------------------------------------------------------
101  //----------------------------------------------------------------------
102  virtual ~Worker()
103  {
104  Stop();
105  }
106 
107  //----------------------------------------------------------------------
109  //----------------------------------------------------------------------
110  void AddWork(ItemT item)
111  {
112  _workQueue.PushBack(item);
113  return;
114  }
115 
116  //----------------------------------------------------------------------
118  //----------------------------------------------------------------------
119  template <typename InputIterator>
120  void AddWork(InputIterator firstIter, InputIterator lastIter)
121  {
122  _workQueue.PushBack(firstIter, lastIter);
123  return;
124  }
125 
126  //----------------------------------------------------------------------
128  //----------------------------------------------------------------------
129  uint32_t QueueLength() const
130  {
131  return _workQueue.Length();
132  }
133 
134  //----------------------------------------------------------------------
137  //----------------------------------------------------------------------
138  bool ReadyForWork() const
139  {
140  return (_keepRunning
141  && ((! _workQueue.MaxLength())
142  || (_workQueue.Length() < _workQueue.MaxLength())));
143  }
144 
145  //----------------------------------------------------------------------
147  //----------------------------------------------------------------------
148  void MaxWork(uint32_t maxItems)
149  {
150  _workQueue.MaxLength(maxItems);
151  }
152 
153  //----------------------------------------------------------------------
155  //----------------------------------------------------------------------
156  bool Start()
157  {
158  bool rc = false;
159  _keepRunning = true;
160  _thread = std::thread(&Worker::Run, this);
161  rc = true;
162  return rc;
163  }
164 
165  //----------------------------------------------------------------------
167  //----------------------------------------------------------------------
168  void Stop()
169  {
170  _keepRunning = false;
171  if (_thread.joinable()) {
172  _thread.join();
173  }
174  return;
175  }
176 
177  //----------------------------------------------------------------------
179  //----------------------------------------------------------------------
180  bool IsRunning()
181  {
182  return (_thread.joinable());
183  }
184 
185  //----------------------------------------------------------------------
187  //----------------------------------------------------------------------
188  void Run()
189  {
190  while (_keepRunning) {
191  if (_workQueue.TimedWaitForNotEmpty(std::chrono::microseconds(_waitUsecs))) {
192  std::deque<ItemT> myCopy;
193  _workQueue.Swap(myCopy);
194  // try processing in bulk
195  if (! ProcessWork(myCopy)) {
196  // else fall back to one at a time.
197  for (auto i : myCopy) {
198  ProcessWork(i);
199  }
200  }
201  }
202  }
203  return;
204  }
205 
206  //----------------------------------------------------------------------
209  //----------------------------------------------------------------------
210  virtual void ProcessWork(ItemT item) = 0;
211 
212  //----------------------------------------------------------------------
216  //----------------------------------------------------------------------
217  virtual bool ProcessWork(std::deque<ItemT> & items)
218  {
219  return false;
220  }
221 
222  protected:
223  Thread::Queue<ItemT> _workQueue;
224  bool _keepRunning;
225  std::thread _thread;
226  uint32_t _waitUsecs;
227  };
228 
229  //------------------------------------------------------------------------
231  //------------------------------------------------------------------------
233  {
234  public:
235  //----------------------------------------------------------------------
238  //----------------------------------------------------------------------
239  bool operator () (const Worker * a,
240  const Worker * b) const
241  {
242  return (a->QueueLength() < b->QueueLength());
243  }
244  };
245 
246  //------------------------------------------------------------------------
248  //------------------------------------------------------------------------
249  void AddWorker(Worker *worker)
250  {
251  _workers.push_back(worker);
252  return;
253  }
254 
255  //------------------------------------------------------------------------
257  //------------------------------------------------------------------------
258  void AddWork(ItemT item)
259  {
260  auto w = std::min_element(_workers.begin(), _workers.end(),
261  CompareWorkers());
262  if (w != _workers.end()) {
263  (*w)->AddWork(item);
264  }
265  return;
266  }
267 
268  //------------------------------------------------------------------------
270  //------------------------------------------------------------------------
271  template <typename InputIterator>
272  void AddWork(InputIterator firstIter, InputIterator lastIter)
273  {
274  while (! WorkerReady()) {
275  usleep(1000);
276  }
277  auto w = std::min_element(_workers.begin(), _workers.end(),
278  CompareWorkers());
279  (*w)->AddWork(firstIter, lastIter);
280  return;
281  }
282 
283  //------------------------------------------------------------------------
285  //------------------------------------------------------------------------
286  void Stop()
287  {
288  for (auto w : _workers) {
289  w->Stop();
290  }
291  return;
292  }
293 
294  //------------------------------------------------------------------------
296  //------------------------------------------------------------------------
297  const std::vector<Worker *> & Workers() const
298  {
299  return _workers;
300  }
301 
302  private:
303  std::vector<Worker *> _workers;
304 
305  //------------------------------------------------------------------------
307  //------------------------------------------------------------------------
308  bool WorkerReady()
309  {
310  bool rc = false;
311  for (auto w : _workers) {
312  if (w->ReadyForWork()) {
313  rc = true;
314  break;
315  }
316  }
317  return rc;
318  }
319 
320  };
321 
322 } // namespace Dwm
323 
324 
325 #endif // _DWMLOADBALANCER_HH_
bool PushBack(const _ValueType &value)
Inserts value on the back of the queue.
Definition: DwmThreadQueue.hh:123
void Run()
Runs the worker thread.
Definition: DwmLoadBalancer.hh:188
void MaxWork(uint32_t maxItems)
Sets the maximum length of the worker&#39;s work queue.
Definition: DwmLoadBalancer.hh:148
bool IsRunning()
Returns true if the worker&#39;s thread is running.
Definition: DwmLoadBalancer.hh:180
virtual ~Worker()
Destructor. Stops the worker thread.
Definition: DwmLoadBalancer.hh:102
virtual void ProcessWork(ItemT item)=0
Pure virtual member to process a single work item.
void Stop()
Calls Worker::Stop() on all encapsulated Worker objects.
Definition: DwmLoadBalancer.hh:286
void AddWork(ItemT item)
Adds a work item for the worker.
Definition: DwmLoadBalancer.hh:110
const std::vector< Worker * > & Workers() const
Returns a const reference to the encapsulated workers.
Definition: DwmLoadBalancer.hh:297
uint32_t Swap(std::deque< _ValueType > &c)
This member is a simple optimization for fetching the contents of the queue.
Definition: DwmThreadQueue.hh:331
bool Start()
Starts the worker.
Definition: DwmLoadBalancer.hh:156
void AddWork(InputIterator firstIter, InputIterator lastIter)
Adds work to be done with load balancing.
Definition: DwmLoadBalancer.hh:272
void AddWork(ItemT item)
Adds work to be done with load balancing.
Definition: DwmLoadBalancer.hh:258
Dwm::SysLogger class definition and Syslog() macro.
void Stop()
Stops the worker.
Definition: DwmLoadBalancer.hh:168
virtual bool ProcessWork(std::deque< ItemT > &items)
Process a deque of work items.
Definition: DwmLoadBalancer.hh:217
uint32_t QueueLength() const
Returns the current length of the worker&#39;s work queue.
Definition: DwmLoadBalancer.hh:129
uint32_t MaxLength() const
Returns the max length of the queue.
Definition: DwmThreadQueue.hh:95
Comparison class for workers within the LoadBalancer.
Definition: DwmLoadBalancer.hh:232
Definition: DwmBZ2IO.hh:67
void AddWork(InputIterator firstIter, InputIterator lastIter)
Adds work items for the worker.
Definition: DwmLoadBalancer.hh:120
Worker class for LoadBalancer.
Definition: DwmLoadBalancer.hh:86
Dwm::Thread::Queue class template definition.
std::deque< _ValueType >::size_type Length() const
Returns the current length of the queue.
Definition: DwmThreadQueue.hh:113
A simple load balancer class template which balances work across Worker objects that each run in thei...
Definition: DwmLoadBalancer.hh:80
bool ReadyForWork() const
Returns true if the worker is ready for more work (has room in its work queue and is running)...
Definition: DwmLoadBalancer.hh:138
void AddWorker(Worker *worker)
Adds the given worker to the load balancer.
Definition: DwmLoadBalancer.hh:249
Worker(uint32_t waitNotEmptyMicroseconds=1000)
Constructs the worker.
Definition: DwmLoadBalancer.hh:94
bool TimedWaitForNotEmpty(const std::chrono::duration< Rep, Period > &timeToWait)
Waits timeToWait for the queue to be non-empty.
Definition: DwmThreadQueue.hh:268