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 
48 namespace Utils {
49 
57  class ThreadPool {
58  public:
59 
65  ThreadPool() = default;
66 
72  ~ThreadPool();
73 
80  void initialize(std::size_t);
81 
88  void add_thread(std::function<void()> initializer);
89 
90  template<class F, class... Args>
99  auto add_task(F&& f, Args&&... args)
100  -> std::future<typename std::result_of<F(Args...)>::type>;
101  private:
102  std::vector<std::thread> m_threads;
103  std::queue<std::function<void()>> m_tasks;
104 
105  std::mutex m_mutex;
106  std::condition_variable m_condvar;
107  bool m_exit{false};
108  };
109 
110  inline void ThreadPool::add_thread(std::function<void()> initializer) {
111  m_threads.emplace_back([this, initializer] {
112  initializer();
113  for (;;) {
114  std::function<void()> task;
115  {
116  std::unique_lock<std::mutex> lock(m_mutex);
117  m_condvar.wait(lock, [this]{ return m_exit || !m_tasks.empty(); });
118  if (m_exit && m_tasks.empty()) {
119  return;
120  }
121  task = std::move(m_tasks.front());
122  m_tasks.pop();
123  }
124  task();
125  }
126  });
127  }
128 
129  inline void ThreadPool::initialize(size_t threads) {
130  for (size_t i = 0; i < threads; i++) {
131  add_thread( [](){} /* null function */);
132  }
133  }
134 
135  template<class F, class... Args>
136  auto ThreadPool::add_task(F&& f, Args&&... args)
137  -> std::future<typename std::result_of<F(Args...)>::type> {
138  using return_type = typename std::result_of<F(Args...)>::type;
139 
140  auto task = std::make_shared< std::packaged_task<return_type()> >(
141  std::bind(std::forward<F>(f), std::forward<Args>(args)...)
142  );
143 
144  std::future<return_type> res = task->get_future();
145  {
146  std::unique_lock<std::mutex> lock(m_mutex);
147  m_tasks.emplace([task](){(*task)();});
148  }
149  m_condvar.notify_one();
150  return res;
151  }
152 
154  {
155  std::unique_lock<std::mutex> lock(m_mutex);
156  m_exit = true;
157  }
158  m_condvar.notify_all();
159  for (std::thread & worker: m_threads) {
160  worker.join();
161  }
162  }
163 
171  class ThreadGroup {
172  public:
179  ThreadGroup(ThreadPool & pool) : m_pool(pool) {}
180 
181  template<class F, class... Args>
189  void add_task(F&& f, Args&&... args) {
190  m_taskresults.emplace_back(
191  m_pool.add_task(std::forward<F>(f), std::forward<Args>(args)...)
192  );
193  }
194 
200  void wait_all() {
201  for (auto && result: m_taskresults) {
202  result.get();
203  }
204  }
205  private:
207  std::vector<std::future<void>> m_taskresults;
208  };
209 }
210 
211 #endif
void add_thread(std::function< void()> initializer)
Add an extra thread.
Definition: ThreadPool.h:110
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:136
ThreadGroup(ThreadPool &pool)
Build a ThreadGroup from a ThreadPool.
Definition: ThreadPool.h:179
void add_task(F &&f, Args &&... args)
Add a task to the thread.
Definition: ThreadPool.h:189
ThreadPool & m_pool
Definition: ThreadPool.h:206
std::mutex m_mutex
Definition: ThreadPool.h:105
An implementation of Thread group.
Definition: ThreadPool.h:171
An implementation of Thread pool.
Definition: ThreadPool.h:57
ThreadPool()=default
Default constructor.
std::vector< std::future< void > > m_taskresults
Definition: ThreadPool.h:207
std::condition_variable m_condvar
Definition: ThreadPool.h:106
std::vector< std::thread > m_threads
Definition: ThreadPool.h:102
~ThreadPool()
Default destructor.
Definition: ThreadPool.h:153
std::queue< std::function< void()> > m_tasks
Definition: ThreadPool.h:103
void wait_all()
Wait until all task results have a valid value.
Definition: ThreadPool.h:200
A set of useful method and class.
Definition: Random.cpp:33
bool m_exit
Definition: ThreadPool.h:107
void initialize(std::size_t)
Create worker threads.
Definition: ThreadPool.h:129