libutil++  1.9.3
 All Classes Functions Variables
ThreadPool.h
1 /*
2 ** libutil++
3 ** $Id: ThreadPool.h 1653 2016-02-28 19:54:59Z sella $
4 ** Copyright (c) 2011-2016 Digital Genesis, LLC. All Rights Reserved.
5 ** Released under the LGPL Version 2.1 License.
6 ** http://www.digitalgenesis.com
7 */
8 
9 #ifndef __libutilxx__sella__util__ThreadPool_H__
10 #define __libutilxx__sella__util__ThreadPool_H__
11 
12 #include "../../common.h"
13 #include "ThreadPoolException.h"
14 #include "Task.h"
15 #include "TaskQueue.h"
16 #include "Log.h"
17 
18 #include <sched.h>
19 
20 #include <set>
21 #include <thread>
22 #include <chrono>
23 #include <condition_variable>
24 
25 #if defined __GNUC__ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
26  #include <atomic> // GCC 4.6 and up
27 #else
28  #include <stdatomic.h> // GCC 4.4 and 4.5 only
29 #endif
30 
31 namespace sella {
32  namespace util {
33  class ThreadPool;
34  }
35 }
36 
37 class sella::util::ThreadPool : protected TaskQueue { /* NOTE: ThreadPool is thread safe. */
38  public:
39  typedef std::shared_ptr<ThreadPool> shared;
40 
41  public:
42  static const size_t DefaultMaximumWorkers = 0; /* 0 to auto assign available core count */
43  static const size_t DefaultMinimumWorkers = 2;
44  static const size_t DefaultSpareWorkers = 2; /* Number of non-active workers. */
45 
46  public:
47  ThreadPool(size_t maximumWorkers = DefaultMaximumWorkers) throw (ThreadPoolException); /* Simple non-scaling pool. */
48  ThreadPool(size_t maximumWorkers, size_t minimumWorkers, size_t spareWorkers = DefaultSpareWorkers) throw (ThreadPoolException); /* Auto-scaling pool. */
49  ThreadPool(Log::shared log, size_t maximumWorkers = DefaultMaximumWorkers) throw (ThreadPoolException);
50  ThreadPool(Log::shared log, size_t maximumWorkers, size_t minimumWorkers, size_t spareWorkers = DefaultSpareWorkers) throw (ThreadPoolException);
51  ThreadPool(const ThreadPool &other) = delete;
52  virtual ~ThreadPool();
53 
54  void schedule(Task::shared &task, int priority = 0);
55  void schedule(Task::shared &task, const std::chrono::system_clock::duration &delay, int priority = 0);
56  void schedule(Task::shared &task, const std::chrono::system_clock::time_point &time, int priority = 0);
57  void schedule(Task::shared &task, time_t sec, suseconds_t usec, int priority = 0);
58  void schedule(Task::shared &task, timeval &tv, int priority = 0);
59  bool reschedule(Task::shared &task, const std::chrono::system_clock::duration &delay, int priority = 0, bool strict = false);
60  bool reschedule(Task::shared &task, const std::chrono::system_clock::time_point &time, int priority = 0, bool strict = false);
61  bool reschedule(Task::shared &task, time_t sec, suseconds_t usec = 0, int priority = 0, bool strict = false);
62  bool reschedule(Task::shared &task, timeval &tv, int priority = 0, bool strict = false);
63  bool unschedule(Task::shared &task, bool firstonly = true);
64 
65  void pause(bool on = true);
66  void resume(void) { pause(false); }
67 
68  size_t getCPUCount(void);
69  int getCPUSetCount(void);
70  bool addCPUAffinity(int cpu);
71  bool addCPUAffinity(std::set<int> cpus);
72  bool setCPUAffinity(cpu_set_t &cpuset);
73  bool clearCPUAffinity(void);
74  bool clearCPUAffinity(int cpu);
75  bool clearCPUAffinity(std::set<int> cpus);
76 
77  size_t size(void) const;
78  size_t workers(void) const;
79  size_t active(void) const;
80  bool empty(void) const;
81  void clear(void);
82 
83  Task::shared next(void);
84  std::chrono::microseconds duration(void) const;
85  std::chrono::microseconds max(void) const;
86  bool ready(void) const;
87 
88  bool wait(void); /* Wait until completely empty */
89  bool wait(const std::chrono::system_clock::duration &delay);
90  bool wait(const std::chrono::system_clock::time_point &time);
91 
92  using TaskQueue::capacity;
93  void reserve(size_t capacity);
94  void print(void) const;
95  using TaskQueue::setLog;
96 
97  static ThreadPool::shared shared_ptr(size_t maximumWorkers = DefaultMaximumWorkers) throw (ThreadPoolException);
98  static ThreadPool::shared shared_ptr(size_t maximumWorkers, size_t minimumWorkers, size_t spareWorkers = DefaultSpareWorkers) throw (ThreadPoolException);
99  static ThreadPool::shared shared_ptr(Log::shared log, size_t maximumWorkers = DefaultMaximumWorkers) throw (ThreadPoolException);
100  static ThreadPool::shared shared_ptr(Log::shared log, size_t maximumWorkers, size_t minimumWorkers, size_t spareWorkers = DefaultSpareWorkers) throw (ThreadPoolException);
101 
102  protected:
103  std::thread managerTID;
104  std::set<pthread_t> tids;
105  std::atomic<size_t> threads;
106  std::atomic<size_t> creating;
107  std::atomic<size_t> actives;
108  std::atomic<size_t> overage;
109  bool shutdown;
110  bool paused;
111  bool allcpus;
112  cpu_set_t cpuset;
113 
114  mutable std::mutex heapMutex;
115  mutable std::mutex tidsMutex;
116  mutable std::mutex managerMutex;
117  mutable std::mutex workerMutex;
118  mutable std::mutex overageMutex;
119  mutable std::mutex emptyMutex;
120  std::condition_variable managerCV;
121  std::condition_variable workerCV;
122  std::condition_variable emptyCV;
123 
124  size_t maximum;
125  size_t minimum;
126  size_t spares;
127 
128  void manager(void);
129  void worker(void);
130  void normalize(void);
131  void createWorker(void);
132  bool setThreadsAffinity(void);
133  bool setThreadAffinity(pthread_t tid);
134 };
135 
136 #endif
137 
138 /*
139 ** vim: noet ts=3 sw=3
140 */