Line data Source code
1 : /* Copyright (c) 2016-2017, Mohamed-Ghaith Kaabi <mohamedghaith.kaabi@gmail.com>
2 : *
3 : * This library is free software; you can redistribute it and/or modify it under
4 : * the terms of the GNU Lesser General Public License version 2.1 as published
5 : * by the Free Software Foundation.
6 : *
7 : * This library is distributed in the hope that it will be useful, but WITHOUT
8 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
10 : * details.
11 : *
12 : * You should have received a copy of the GNU Lesser General Public License
13 : * along with this library; if not, write to the Free Software Foundation, Inc.,
14 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15 : */
16 :
17 : #pragma once
18 :
19 : #include <lunchbox/api.h>
20 :
21 : #include <condition_variable> // member
22 : #include <functional>
23 : #include <future> // inline return value
24 : #include <queue> // member
25 : #include <thread> // member
26 : #include <vector> // member
27 :
28 : namespace lunchbox
29 : {
30 : /**
31 : * Thread pool for tasks execution.
32 : * A task is a callable object taking no arguments and returing a value or void.
33 : * All the member methods are thread safe.
34 : *
35 : * Example: @include tests/threadPool.cpp
36 : */
37 : class ThreadPool
38 : {
39 : public:
40 : /** @return the application-global thread pool. */
41 : static LUNCHBOX_API ThreadPool& getInstance();
42 :
43 : /**
44 : * Construct a new ThreadPool.
45 : *
46 : * @param size number of threads in the thread pool
47 : * @sa getInstance() for the recommended thread pool.
48 : */
49 : LUNCHBOX_API ThreadPool(const size_t size);
50 : /**
51 : * Destroy this thread pool.
52 : * Will block until all the tasks are done.
53 : */
54 : LUNCHBOX_API ~ThreadPool();
55 :
56 : /**
57 : * @return the number of threads used in the thread pool
58 : */
59 : LUNCHBOX_API size_t getSize() const;
60 :
61 : /**
62 : * Post a new task in the thread pool.
63 : * @return a std::future containing the future result.
64 : */
65 : template <typename F>
66 : inline std::future<typename std::result_of<F()>::type> post(F&& f);
67 :
68 : /**
69 : * Post a detached task in the thread pool.
70 : * The result of this task is not monitored.
71 : */
72 : template <typename F>
73 : inline void postDetached(F&& f);
74 :
75 : /** @return true if there are pending tasks to be executed. */
76 : LUNCHBOX_API bool hasPendingJobs() const;
77 :
78 : private:
79 : ThreadPool(const ThreadPool&) = delete;
80 : ThreadPool(ThreadPool&&) = delete;
81 : ThreadPool& operator=(const ThreadPool&) = delete;
82 : ThreadPool& operator=(ThreadPool&&) = delete;
83 :
84 : LUNCHBOX_API void joinAll();
85 : LUNCHBOX_API void work();
86 :
87 : std::vector<std::thread> _threads;
88 : std::queue<std::function<void()> > _tasks;
89 : mutable std::mutex _mutex;
90 : std::condition_variable _condition;
91 : bool _stop;
92 : };
93 :
94 : template <typename F>
95 133 : std::future<typename std::result_of<F()>::type> ThreadPool::post(F&& f)
96 : {
97 : using ReturnType = typename std::result_of<F()>::type;
98 :
99 : auto task =
100 266 : std::make_shared<std::packaged_task<ReturnType()> >(std::forward<F>(f));
101 :
102 133 : auto res = task->get_future();
103 : {
104 266 : std::unique_lock<std::mutex> lock(_mutex);
105 835 : _tasks.emplace([task]() { (*task)(); });
106 : }
107 133 : _condition.notify_one();
108 266 : return res;
109 : }
110 :
111 : template <typename F>
112 10 : void ThreadPool::postDetached(F&& f)
113 : {
114 : {
115 20 : std::unique_lock<std::mutex> lock(_mutex);
116 10 : _tasks.emplace(f);
117 : }
118 10 : _condition.notify_one();
119 10 : }
120 : }
|