jGL
Loading...
Searching...
No Matches
jThread.h
Go to the documentation of this file.
1#ifndef THREADPOOL_H
2#define THREADPOOL_H
3
4#include <thread>
5#include <mutex>
6#include <condition_variable>
7#include <queue>
8#include <functional>
9#include <assert.h>
10
11/*
12
13 jThread a quick and dirty header only multi-threading library
14
15*/
16
17// MIT License
18
19// Copyright (c) 2024 Jerboa
20
21// Permission is hereby granted, free of charge, to any person obtaining a copy
22// of this software and associated documentation files (the "Software"), to deal
23// in the Software without restriction, including without limitation the rights
24// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25// copies of the Software, and to permit persons to whom the Software is
26// furnished to do so, subject to the following conditions:
27
28// The above copyright notice and this permission notice shall be included in all
29// copies or substantial portions of the Software.
30
31// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37// SOFTWARE.
38
39/*
40
41 stack overflows
42 https://stackoverflow.com/questions/26516683/reusing-thread-in-loop-c
43 https://stackoverflow.com/questions/15752659/thread-pooling-in-c11
44 https://stackoverflow.com/questions/3929774/how-much-overhead-is-there-when-creating-a-thread
45 https://stackoverflow.com/questions/17348228/code-runs-6-times-slower-with-2-threads-than-with-1
46
47 ThreadPool pool(n) - spawn n threads (beware hardware concurrency limits: https://en.cppreference.com/w/cpp/thread/thread/hardware_concurrency)
48
49 pool.queueJob(std::bind(work,std::ref(a),std::ref(b),std::ref(c2))); - enqueue the function, work, with 3 arguments (as references)
50
51 pool.wait() - waits until all jobs are done
52 pool.stop() - stops (joins) threads (will interrupt threads if the have not already consumed a job on the queue)
53
54*/
55namespace jThread
56{
57
59 {
60
61 public:
62
63 ThreadPool(size_t n)
64 : nThreads(n), terminate(false), working(0)
65 {
66 threads.resize(n);
67 for (unsigned i = 0; i < n; i++)
68 {
69 threads[i] = std::thread(&ThreadPool::main,this);
70 }
71 }
72
73 void queueJob(const std::function<void(void)> & job)
74 {
75 {
76 std::unique_lock<std::mutex> lock(queueLock);
77 jobs.emplace(std::move(job));
78 // increment work to do/work inprogress counter
79 working++;
80 } // release mutex
81 queueCondition.notify_one();
82 }
83
84 bool busy()
85 {
86 bool b = false;
87 {
88 std::unique_lock<std::mutex> lock(queueLock);
89 // if work is still to do or still in progress pool is busy
90 b = working > 0;
91 } // release mutex
92 return b;
93 }
94
95 void wait()
96 {
97 while (busy())
98 {
99 //void
100 }
101 }
102
103 void stop()
104 {
105 {
106 std::unique_lock<std::mutex> lock(queueLock);
107 terminate = true;
108 } // release mutex
109 queueCondition.notify_all();
110 for (std::thread & t : threads)
111 {
112 t.join();
113 }
114 threads.clear();
115 }
116
118 {
119 stop();
120 }
121
123 {
124 size_t n = size();
125 if (n > 0)
126 {
127
128 stop();
129 terminate = false;
130 threads.resize(n-1);
131
132 for (unsigned i = 0; i < n-1; i++)
133 {
134 threads[i] = std::thread(&ThreadPool::main,this);
135 }
136 }
137 }
138
139 void joinAll()
140 {
141 while (size() > 0)
142 {
143 joinThread();
144 }
145 }
146
148 {
149 size_t n = size();
150 if (n < nThreads)
151 {
152 stop();
153 terminate = false;
154 threads.resize(n+1);
155 for (unsigned i = 0; i < n+1; i++)
156 {
157 threads[i] = std::thread(&ThreadPool::main,this);
158 }
159 }
160 }
161
162 size_t size(){return threads.size();}
163
164 private:
165
166 void main()
167 {
168 while (true)
169 {
170 std::function<void(void)> job;
171 {
172 std::unique_lock<std::mutex> lock(queueLock);
173
174 queueCondition.wait(
175 lock, [this] {return !jobs.empty() || terminate;}
176 );
177
178 if (terminate)
179 {
180 return;
181 }
182
183 job = std::move(jobs.front());
184 jobs.pop();
185 } // release mutex
186
187 job();
188
189 {
190 std::unique_lock<std::mutex> lock(queueLock);
191 // decrement work being done/to do
192 working--;
193 }
194 }
195 }
196
197 const size_t nThreads;
198
199 bool terminate;
200
201 std::queue<std::function<void(void)>> jobs;
202 std::vector<std::thread> threads;
203
204 size_t working;
205
206 std::mutex queueLock;
207 std::condition_variable queueCondition;
208
209 };
210}
211#endif /* THREADPOOL_H */
Definition jThread.h:59
~ThreadPool()
Definition jThread.h:117
void queueJob(const std::function< void(void)> &job)
Definition jThread.h:73
void stop()
Definition jThread.h:103
ThreadPool(size_t n)
Definition jThread.h:63
bool busy()
Definition jThread.h:84
size_t size()
Definition jThread.h:162
void createThread()
Definition jThread.h:147
void joinAll()
Definition jThread.h:139
void wait()
Definition jThread.h:95
void joinThread()
Definition jThread.h:122
Definition jThread.h:56