MLIB
Loading...
Searching...
No Matches
thread.h
Go to the documentation of this file.
1/*
2 Copyright (c) Mircea Neacsu (2014-2025) Licensed under MIT License.
3 This file is part of MLIB project. See LICENSE file for full license terms.
4*/
5
7
8#pragma once
9
10#include "event.h"
11#include <functional>
12
13namespace mlib {
14
16class thread : public syncbase
17{
18public:
19
29
31 thread (std::function<unsigned int ()> func);
32
33 virtual ~thread ();
34
36 virtual void start ();
37
39 void fork ();
40
42 void join ();
43
45 DWORD wait (DWORD time_limit = INFINITE);
46
48 DWORD wait_alertable (DWORD time_limit = INFINITE);
49
51 DWORD wait_msg (DWORD time_limit = INFINITE, DWORD mask = QS_ALLINPUT);
52
54 void rethrow_exception () const;
55
57 DWORD id () const;
58
60 UINT result () const;
61
63 bool is_running () const;
64
66 state get_state () const;
67
69 int priority () const;
70
72 void priority (int pri);
73
74 using syncbase::name;
75
77 virtual void name (const std::string& nam);
78
79protected:
81 thread (const std::string& name = std::string (), DWORD stack_size = 0,
82 PSECURITY_DESCRIPTOR sd = NULL, bool inherit = false);
83
85 virtual bool init ();
86
88 virtual void term ();
89
91 virtual void run ();
92
93 unsigned int exitcode;
94
95private:
96 void initialize (PSECURITY_DESCRIPTOR sd, BOOL inherit);
97 thread& operator= (const thread& t) = delete;
98 thread (const thread& t) = delete;
99
100 DWORD id_;
101 state volatile stat;
102 auto_event created, started;
103 static unsigned int _stdcall entryProc (thread* ts);
104 DWORD stack;
105 std::function<unsigned int ()> thfunc;
106 std::exception_ptr pex;
107};
108
116{
117public:
118 DWORD id () const;
119 HANDLE handle () const;
120 int priority ();
121 void priority (int pri);
122};
123
124// inlines
125
126inline void thread::fork ()
127{
128 start ();
129}
130
131inline void thread::join ()
132{
133 wait (INFINITE);
134}
135
136inline DWORD thread::id () const
137{
138 return id_;
139};
140
141inline UINT thread::result () const
142{
143 return exitcode;
144}
145
146inline bool thread::is_running () const
147{
148 return stat == state::running;
149}
150
152{
153 return stat;
154}
155
156inline int thread::priority () const
157{
158 return GetThreadPriority (handle ());
159}
160
161inline void thread::priority (int pri)
162{
163 SetThreadPriority (handle (), pri);
164}
165
166inline bool thread::init ()
167{
168 return true;
169}
170
171inline void thread::term ()
172{
173}
174
175inline void thread::rethrow_exception () const
176{
177 if (pex)
178 std::rethrow_exception (pex);
179}
180
181// ----------- current_thread inline functions ------------------------------
182
184inline DWORD current_thread::id () const
185{
186 return GetCurrentThreadId ();
187}
188
189inline HANDLE current_thread::handle () const
190{
191 return GetCurrentThread ();
192}
193
196{
197 return GetThreadPriority (GetCurrentThread ());
198}
199
201inline void current_thread::priority (int pri)
202{
203 SetThreadPriority (GetCurrentThread (), pri);
204}
205
213
214template <typename T>
215concept ThreadDerived = std::derived_from<T, mlib::thread>;
216
217template <ThreadDerived T>
218inline DWORD wait_all (const T* objs, int count, DWORD msec = INFINITE)
219{
220 assert (count < MAXIMUM_WAIT_OBJECTS);
221 HANDLE harr[MAXIMUM_WAIT_OBJECTS];
222 for (int i = 0; i < count; i++)
223 harr[i] = objs[i].handle ();
224
225 DWORD result = WaitForMultipleObjects (count, harr, true, msec);
226 if (result < WAIT_OBJECT_0 + count)
227 {
228 for (int i = 0; i < count; i++)
229 objs[i].rethrow_exception ();
230 }
231
232 return result;
233}
234
235template <ThreadDerived T>
236inline DWORD wait_all (std::initializer_list<const T*> objs, std::chrono::milliseconds limit)
237{
238 assert (objs.size () < MAXIMUM_WAIT_OBJECTS);
239 HANDLE harr[MAXIMUM_WAIT_OBJECTS];
240 int i = 0;
241 for (auto& th : objs)
242 harr[i++] = th->handle ();
243
244 DWORD msec = (DWORD)limit.count ();
245 DWORD result = WaitForMultipleObjects ((DWORD)objs.size (), harr, true, msec);
246 if (result < WAIT_OBJECT_0 + objs.size ())
247 {
248 for (auto& th : objs)
249 th->rethrow_exception ();
250 }
251
252 return result;
253}
254
255template <ThreadDerived T>
256inline DWORD wait_all (std::initializer_list<const T*> objs, DWORD msec = INFINITE)
257{
258 assert (objs.size () < MAXIMUM_WAIT_OBJECTS);
259 HANDLE harr[MAXIMUM_WAIT_OBJECTS];
260 int i = 0;
261 for (auto& th : objs)
262 harr[i++] = th->handle ();
263
264 DWORD result = WaitForMultipleObjects ((DWORD)objs.size (), harr, true, msec);
265 if (result < WAIT_OBJECT_0 + objs.size ())
266 {
267 for (auto& th : objs)
268 th->rethrow_exception ();
269 }
270
271 return result;
272}
273
274template <ThreadDerived T>
275inline DWORD wait_any (const T* objs, int count, DWORD msec = INFINITE)
276{
277 assert (count < MAXIMUM_WAIT_OBJECTS);
278 HANDLE harr[MAXIMUM_WAIT_OBJECTS];
279 for (int i = 0; i < count; i++)
280 harr[i] = objs[i].handle ();
281
282 DWORD result = WaitForMultipleObjects (count, harr, false, msec);
283 if (result < WAIT_OBJECT_0 + count)
284 {
285 for (int i = 0; i < count; i++)
286 objs[i].rethrow_exception ();
287 }
288 return result;
289}
290
291template <ThreadDerived T>
292inline DWORD wait_any (std::initializer_list<const T*> objs, DWORD msec = INFINITE)
293{
294 assert (objs.size () < MAXIMUM_WAIT_OBJECTS);
295 HANDLE harr[MAXIMUM_WAIT_OBJECTS];
296 int i = 0;
297 for (auto& th : objs)
298 harr[i++] = th->handle ();
299
300 DWORD result = WaitForMultipleObjects ((DWORD)objs.size (), harr, false, msec);
301 if (result < WAIT_OBJECT_0 + objs.size ())
302 {
303 for (auto& th : objs)
304 th->rethrow_exception ();
305 }
306 return result;
307}
308
309template <ThreadDerived T>
310inline DWORD wait_any (std::initializer_list<const T*> objs, std::chrono::milliseconds timeout)
311{
312 assert (objs.size () < MAXIMUM_WAIT_OBJECTS);
313 HANDLE harr[MAXIMUM_WAIT_OBJECTS];
314 int i = 0;
315 for (auto& th : objs)
316 harr[i++] = th->handle ();
317 DWORD msec = (DWORD)timeout.count ();
318 DWORD result = WaitForMultipleObjects ((DWORD)objs.size (), harr, false, msec);
319 if (result < WAIT_OBJECT_0 + objs.size ())
320 {
321 for (auto& th : objs)
322 th->rethrow_exception ();
323 }
324 return result;
325}
326
327template <ThreadDerived T>
328inline DWORD wait_msg (const T* objs, int count, bool all = true, DWORD msec = INFINITE,
329 DWORD mask = QS_ALLINPUT)
330{
331 assert (count < MAXIMUM_WAIT_OBJECTS);
332 HANDLE harr[MAXIMUM_WAIT_OBJECTS];
333 for (int i = 0; i < count; i++)
334 harr[i] = objs[i].handle ();
335
336 DWORD result = MsgWaitForMultipleObjects (count, harr, all, msec, mask);
337 if (result < WAIT_OBJECT_0 + count)
338 {
339 for (int i = 0; i < count; i++)
340 objs[i].rethrow_exception ();
341 }
342 return result;
343}
344
345template <ThreadDerived T>
346inline DWORD wait_msg (std::initializer_list<const T*> objs, bool all = true, DWORD msec = INFINITE,
347 DWORD mask = QS_ALLINPUT)
348{
349 assert (objs.size () < MAXIMUM_WAIT_OBJECTS);
350 HANDLE harr[MAXIMUM_WAIT_OBJECTS];
351 int i = 0;
352 for (auto& th : objs)
353 harr[i++] = th->handle ();
354
355 DWORD result = MsgWaitForMultipleObjects ((DWORD)objs.size (), harr, all, msec, mask);
356 if (result < WAIT_OBJECT_0 + objs.size ())
357 {
358 for (auto& th : objs)
359 th->rethrow_exception ();
360 }
361 return result;
362}
363
365
366} // namespace mlib
Event objects that reset automatically after a successful wait.
Definition event.h:50
Currently executing thread object.
Definition thread.h:116
HANDLE handle() const
Return handle of current thread.
Definition thread.h:189
DWORD id() const
Return ID of current thread.
Definition thread.h:184
int priority()
Return priority of current thread.
Definition thread.h:195
HANDLE handle() const
Return OS handle of this object.
Definition syncbase.h:53
syncbase()
Default constructor.
Definition syncbase.cpp:37
virtual void wait()
Wait for object to become signaled.
Definition syncbase.h:85
virtual const std::string & name() const
Return object's name.
Definition syncbase.h:59
void fork()
Another name for start () function.
Definition thread.h:126
DWORD wait_msg(DWORD time_limit=INFINITE, DWORD mask=QS_ALLINPUT)
Wait for thread to finish or a message to be queued.
Definition thread.cpp:218
state get_state() const
Return thread's execution status.
Definition thread.h:151
virtual bool init()
Initialization function called before run.
Definition thread.h:166
void rethrow_exception() const
Rethrow an exception usually in the context of another thread.
Definition thread.h:175
bool is_running() const
Return true if thread is running.
Definition thread.h:146
DWORD wait_alertable(DWORD time_limit=INFINITE)
Wait for thread to finish or an APC, or IO completion routine to occur.
Definition thread.cpp:200
virtual void run()
Default run function.
Definition thread.cpp:147
int priority() const
Return thread's priority.
Definition thread.h:156
state
Execution state of a thread.
Definition thread.h:22
@ starting
in the process of starting up
Definition thread.h:24
@ running
is running
Definition thread.h:25
@ finished
execution finished
Definition thread.h:27
@ ready
not started
Definition thread.h:23
@ ending
in the process of finishing
Definition thread.h:26
UINT result() const
Return thread's exit code.
Definition thread.h:141
virtual ~thread()
Destructor.
Definition thread.cpp:98
void join()
Another name for wait () function.
Definition thread.h:131
DWORD id() const
Return thread's ID.
Definition thread.h:136
thread(std::function< unsigned int()> func)
Make a thread with the given function body.
Definition thread.cpp:64
virtual void term()
Finalization function called after run.
Definition thread.h:171
virtual void start()
Begin execution of a newly created thread.
Definition thread.cpp:161
unsigned int exitcode
exit code
Definition thread.h:93
virtual const std::string & name() const
Return object's name.
Definition syncbase.h:59
Specialization of wait functions for threads, re-throw any exceptions that might have occurred during...
Definition thread.h:215
Definition of mlib::event class.
DWORD wait_any(const T *objs, int count, DWORD msec=INFINITE)
Wait for multiple objects until any of them becomes signaled.
Definition syncbase.h:243
DWORD wait_all(const T *objs, int count, DWORD msec=INFINITE)
Wait for multiple objects until all become signaled.
Definition syncbase.h:170
DWORD wait_msg(const T *objs, int count, bool all=true, DWORD msec=INFINITE, DWORD mask=QS_ALLINPUT)
Wait for multiple objects or a message to be queued.
Definition syncbase.h:317