IAtari
Genetic algorithm generating AI capable to play Atari2600 games.
ThreadPool.h
Go to the documentation of this file.
1 #ifndef THREADPOOL_H_INCLUDED
2 #define THREADPOOL_H_INCLUDED
3 /*
4  Extended from code:
5  Copyright (c) 2012 Jakob Progsch, Václav Zeman
6 
7  This software is provided 'as-is', without any express or implied
8  warranty. In no event will the authors be held liable for any damages
9  arising from the use of this software.
10 
11  Permission is granted to anyone to use this software for any purpose,
12  including commercial applications, and to alter it and redistribute it
13  freely, subject to the following restrictions:
14 
15  1. The origin of this software must not be misrepresented; you must not
16  claim that you wrote the original software. If you use this software
17  in a product, an acknowledgment in the product documentation would be
18  appreciated but is not required.
19 
20  2. Altered source versions must be plainly marked as such, and must not be
21  misrepresented as being the original software.
22 
23  3. This notice may not be removed or altered from any source
24  distribution.
25 */
26 
27 #include <cstddef>
28 #include <vector>
29 #include <thread>
30 #include <queue>
31 #include <mutex>
32 #include <condition_variable>
33 #include <memory>
34 #include <future>
35 #include <functional>
36 
42 namespace Utils {
43 
51  class ThreadPool {
52  public:
53 
59  ThreadPool() = default;
60 
66  ~ThreadPool();
67 
74  void initialize(std::size_t);
75 
82  void add_thread(std::function<void()> initializer);
83 
84  template<class F, class... Args>
93  auto add_task(F&& f, Args&&... args)
94  -> std::future<typename std::result_of<F(Args...)>::type>;
95  private:
96  std::vector<std::thread> m_threads;
97  std::queue<std::function<void()>> m_tasks;
98 
99  std::mutex m_mutex;
100  std::condition_variable m_condvar;
101  bool m_exit{false};
102  };
103 
104  inline void ThreadPool::add_thread(std::function<void()> initializer) {
105  m_threads.emplace_back([this, initializer] {
106  initializer();
107  for (;;) {
108  std::function<void()> task;
109  {
110  std::unique_lock<std::mutex> lock(m_mutex);
111  m_condvar.wait(lock, [this]{ return m_exit || !m_tasks.empty(); });
112  if (m_exit && m_tasks.empty()) {
113  return;
114  }
115  task = std::move(m_tasks.front());
116  m_tasks.pop();
117  }
118  task();
119  }
120  });
121  }
122 
123  inline void ThreadPool::initialize(size_t threads) {
124  for (size_t i = 0; i < threads; i++) {
125  add_thread( [](){} /* null function */);
126  }
127  }
128 
129  template<class F, class... Args>
130  auto ThreadPool::add_task(F&& f, Args&&... args)
131  -> std::future<typename std::result_of<F(Args...)>::type> {
132  using return_type = typename std::result_of<F(Args...)>::type;
133 
134  auto task = std::make_shared< std::packaged_task<return_type()> >(
135  std::bind(std::forward<F>(f), std::forward<Args>(args)...)
136  );
137 
138  std::future<return_type> res = task->get_future();
139  {
140  std::unique_lock<std::mutex> lock(m_mutex);
141  m_tasks.emplace([task](){(*task)();});
142  }
143  m_condvar.notify_one();
144  return res;
145  }
146 
148  {
149  std::unique_lock<std::mutex> lock(m_mutex);
150  m_exit = true;
151  }
152  m_condvar.notify_all();
153  for (std::thread & worker: m_threads) {
154  worker.join();
155  }
156  }
157 
165  class ThreadGroup {
166  public:
173  ThreadGroup(ThreadPool & pool) : m_pool(pool) {}
174 
175  template<class F, class... Args>
183  void add_task(F&& f, Args&&... args) {
184  m_taskresults.emplace_back(
185  m_pool.add_task(std::forward<F>(f), std::forward<Args>(args)...)
186  );
187  }
188 
194  void wait_all() {
195  for (auto && result: m_taskresults) {
196  result.get();
197  }
198  }
199  private:
200  ThreadPool & m_pool;
201  std::vector<std::future<void>> m_taskresults;
202  };
203 }
204 
205 #endif
void add_thread(std::function< void()> initializer)
Add an extra thread.
Definition: ThreadPool.h:104
auto add_task(F &&f, Args &&... args) -> std::future< typename std::result_of< F(Args...)>::type >
Add a task to the thread.
Definition: ThreadPool.h:130
ThreadGroup(ThreadPool &pool)
Build a ThreadGroup from a ThreadPool.
Definition: ThreadPool.h:173
void add_task(F &&f, Args &&... args)
Add a task to the thread.
Definition: ThreadPool.h:183
An implementation of Thread group.
Definition: ThreadPool.h:165
An implementation of Thread pool.
Definition: ThreadPool.h:51
ThreadPool()=default
Default constructor.
~ThreadPool()
Default destructor.
Definition: ThreadPool.h:147
void wait_all()
Wait until all task results have a valid value.
Definition: ThreadPool.h:194
A set of useful method and class.
Definition: Random.cpp:27
void initialize(std::size_t)
Create worker threads.
Definition: ThreadPool.h:123