Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
Thread.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Execution_Thread_h_
5#define _Stroika_Foundation_Execution_Thread_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <functional>
10#include <map>
11#include <optional>
12#include <thread>
13
14#include "Stroika/Foundation/Common/Common.h"
16#include "Stroika/Foundation/Execution/Exceptions.h"
17#include "Stroika/Foundation/Execution/Signals.h"
20
21/**
22 * \file
23 *
24 * TODO
25 * @todo Probably no longer need siginterrupt () calls, since we DON'T set SA_RESTART in our call to sigaction().
26 */
28 class String;
29}
30
32
33 /**
34 * This is only meant for debugging. If true, track the running threads (and provide API to access)
35 * and DbgTrace() automatically in construction/destruction.
36 */
37#ifndef qStroika_Foundation_Execution_Thread_SupportThreadStatistics
38#define qStroika_Foundation_Execution_Thread_SupportThreadStatistics qStroika_Foundation_Debug_AssertionsChecked
39#endif
40
41 /**
42 * \brief Thread is a namespace for Stroika thread code, @see Thread::Ptr or @Thread::New
43 *
44 * Stroika Threads are built on std::jthread, so can be used mostly interoperably. However,
45 * Stroika threads add a number of very useful features to std::threads:
46 * o Simpler Cancelation/Interruption/Aborting
47 * (c++ 20 introduces thread cancelation via explicitly managed stop_tokens, but Stroika's thread cancelation
48 * uses this, but hides it - mostly).
49 * o EINTR handling (POSIX only)
50 *
51 * as well as a couple modestly helpful features (that can be done other ways directly with std::thread):
52 * o Copyability (using Thread::Ptr)
53 * o Better lifetime management (the thread envelope - object you create - can go away, but
54 * the underlying thread can continue running, with its memory/resources being cleaned
55 * up autoamtically.
56 * o And several minor features like (mostly) portably setting thread priorities, names, etc and more
57 *
58 * Note - the cancelation feature is very handy for building large scale applications which use
59 * worker tasks and things like thread pools, to be able to reclaim resources, cancel ongoing operations
60 * as useless, and maintain overall running system integrity.
61 *
62 * Using the smartpointer wrapper Thread around a thread guarantees its reference counting
63 * will work safely - so that even when all external references go away, the fact that the thread
64 * is still running will keep the reference count non-zero.
65 *
66 * Thread Aborting:
67 * The Stroika Thread class supports the idea of 'aborting' a thread (cooperatitve cancelation)
68 *
69 * Thread Interruoption:
70 * Stroika v2.1 and earlier supported a feature like Thread-Abort, called 'Interrupt' - that acted like
71 * thread abort, except that it was not sticky - and once the interrupt was handled, it 'reset' to not
72 * interrupting anymore.
73 *
74 * I never really found any compelling use case for this idea (borrowed from java thread interrupt).
75 *
76 * And I think the scenarios where it MIGHT be helpful, could be handled just as easily with
77 * condition variables.
78 *
79 * Also, c++20 added support which allows thead aborting (stop_token), but that doesn't work well/easily
80 * for basic interruption.
81 *
82 * So - abandoned Thread::Interrupt(...) in Stroika v3.
83 *
84 * \em Nomenclature Note:
85 * In some libraries, the term interruption, cancelation is used for thread aborting.
86 * > java uses interruption
87 * > boost uses cancelation,
88 * > POSIX uses cancelation (pthread_canel)
89 * > and .net uses Interrupt and Abort
90 *
91 * The basic idea is that a thread goes off on its own, doing stuff, and an external force
92 * decides to tell it to stop.
93 *
94 * Examples of this might be:
95 * (1) A search user interface, which starts searching as the user types. Once the process
96 * has received a certain number of characters it starts searching, but perhaps before
97 * the search is done, another character comes in, so the GUI code will want to Abort
98 * the existing search, and start a new one (with the extra character(s)).
99 * (2) A web server - which is serving up content, and it told to shut-down. It must interrupt
100 * existing in process processes - some maybe handling a read/write sequence, and some
101 * perhaps doing a socket listen/accept call.
102 *
103 * When a thread is aborted, it (in that thread) throws
104 * class AbortException;
105 *
106 * Thread 'interruption' happens via 'cancelation points'. Cancelation points are points in the code
107 * where we check to see if the current running thread has been interrupted (or aborted) and raise
108 * the appropriate exception.
109 *
110 * This mechanism is almost completely co-operative, meaning that user
111 * code must call CheckForInterruption () in the right places to make interruption work. But Stroika
112 * is structured to make that happen automatically throughout most of its code, but having key routines (like Sleep, and WaitableEvents)
113 * automatically internally be cancelation points.
114 *
115 * The only slight exception to this is on Windows, where we have the APC mechanism that will interupt a wide vareity of windows
116 * system calls (see docs below).
117 *
118 * \note - its important that this 'interruption' can only happen at well defined times, because that allows
119 * for safe and reliable cleanup of whatever activitites were being done (e.g. cannot interupt in a destructor)
120 *
121 * Thread interruption/aborting is tricky todo safely and portably. We take a safe, cooperative approach.
122 * (1) We maintain a thread-local-storage variable - saying if this thread has been aborted.
123 * Sprinkling CheckForInterruption throughout your code - will trigger an InterupptedException () or AbortException ()
124 * in that thread context. Note a pointer to that TLS interruption variable is also stored
125 * in the thread 'rep' object, so it can be set (by Thread::Interrupt).
126 *
127 * (2) WINDOWS ONLY: Async-injection (QueueUserAPC/Windows) - Alertable state - certain (alertable) functions get interrupted and return
128 * WAIT_IO_COMPLETION (like POSIX EINTR).
129 *
130 * @see https://msdn.microsoft.com/en-us/library/windows/desktop/aa363772(v=vs.85).aspx
131 * o SleepEx
132 * o WaitForSingleObjectEx
133 * o WaitForMultipleObjectsEx
134 * o SignalObjectAndWait
135 * o MsgWaitForMultipleObjectsEx
136 * But also from https://msdn.microsoft.com/en-us/library/windows/desktop/ms741669(v=vs.85).aspx
137 * o WSAPoll ... Winsock performs an alertable, similarly for recvfrom, accept, etc. Not clear how to get full list of
138 * windows alertable functions...
139 *
140 * This allows interrupting windows waiting / blocking functions (most of them).
141 *
142 * (3) POSIX ONLY: Signal injection - we send a special (defaults to SIG_USR2) signal to a particular thread.
143 * This triggers an EINTR on most UNIX system calls, which are automatically restarted in most cases
144 * (@see Execution::Handle_ErrNoResultInterruption), but in case of interruption, we call
145 * CheckForInterruption ()
146 *
147 * This allows interrupting UNIX waiting / blocking functions (all of them?).
148 *
149 * \note @see defails on cancelation points, because many common std C++ blocking operations, like std::mutex are not
150 * std::condition_variable are not cancelation points and so can break this mechanism if not used carefully
151 *
152 * Handle_ErrNoResultInterruption()
153 * The short of it is that you need to catch EINTR and restart the call for these system calls:
154 * o read, readv, write, writev, ioctl
155 * o open() when dealing with a fifo
156 * o wait*
157 * o Anything socket based (send*, recv*, connect, accept etc)
158 * o flock and lock control with fcntl
159 * o mq_ functions which can block
160 * o futex
161 * o sem_wait (and timed wait)
162 * o pause, sigsuspend, sigtimedwait, sigwaitinfo
163 * o poll, epoll_wait, select and 'p' versions of the same
164 * o msgrcv, msgsnd, semop, semtimedop
165 * o close (although, on Linux, EINTR won't happen here)
166 * o any sleep functions (careful, you need to handle this are restart with
167 * different arguments)
168 * This is integrated with Stroika's thread cancelation mechanism.
169 *
170 * @see Handle_ErrNoResultInterruption
171 *
172 * ***Thread Cancelation Points***
173 * A cancelation point is any (typically but not always blocking) function which will be interrupted (cause interruption exception) and stop blocking,
174 * when someone calls Thread::Interupt or Thread::Abort() on its thread object.
175 *
176 * Roughly, these are subroutines which call
177 * CheckForInterruption ()
178 * frequently, internally.
179 *
180 * As its crucial to understand this in the API, we document each such function with ***Cancelation Point*** in its doc header.
181 * For example, the Sleep() overloads are cancelation points.
182 *
183 * Equally important to understand, is when a function guarantees its NOT a cancelation point - which we will document
184 * with ***Not Cancelation Point***, and typically also noexcept. The DbgTrace () calls fall into this category.
185 *
186 * \note An API marked *** Cancelation Point *** will always CheckForInterruption () at least once (or equivalent check)
187 * and will never block indefinitely without periodically checking for interruption.
188 *
189 * \note Stroika threads lifetime must NOT extend outside the lifetime of 'main'. That means they cannot
190 * be started by static constructors, and must not be left running past the end of main, to
191 * be shut down by static destructors. The reason for this is that its too hard to guarantee
192 * all the rest of the Stroika infrastructure (signals etc) work properly in that context,
193 * and its do overwhemlingly likely a softare bug waiting to happen.
194 *
195 * If you must have a thread running like that, use std::thread (though I'm not sure how well that
196 * will work either).
197 *
198 * Note the Thread 'smartpointer' wrapper can be constructed/destructed statically (before/after main). You
199 * just cannot start a thread before main, nor allow it to still be running (not completed) before exiting.
200 * #if qStroika_Foundation_Execution_Thread_SupportThreadStatistics (defaults true in debug builds) an attempt
201 * is made to auto-detect this and diagnose it in the tracelog and with assertions.
202 *
203 * \note Considered adding an API to return the underlying std::thread or std::thread::native_handle (), but
204 * have not needed this so far, and it might create some confusion about ownership? Detaching would be
205 * a problem because the owned thread object has hooks into the Stroika Thread object, so that kind of
206 * needs to be left around. I suppose we might want to allow an accessor to std::thread* which is like an
207 * internal pointer (thread safety questions too with that). MAYBE better to just allow construction of a
208 * Stroika Thread from an std::thread (but then we don't have the wrapper logic for maining reference counts).
209 * No compelling need so far, and no obviously best approach.
210 */
211 namespace Thread {
212
213 /**
214 * Thread::IDType is a portable representation which is a key to currently existing system threads.
215 */
216 using IDType = thread::id;
217
218 /**
219 * Thread::native_handle is the type of the underlying handle to a native thread
220 * which can allow for using platform APIs.
221 */
222 using NativeHandleType = thread::native_handle_type;
223
224 /**
225 * \brief EXPERIMENTAL SUPPORT FOR THREAD STACK (and maybe other) settings
226 *
227 * @todo COULD add things like CPU afinity, or thread prority.
228 *
229 * These configuration describe how Stroika will construct new Stroika Thread objects.
230 */
232 /**
233 * \note see http://stroika-bugs.sophists.com/browse/STK-474 - @todo and NYI
234 */
235 optional<size_t> fStackSize;
236
237 /**
238 * \note see http://stroika-bugs.sophists.com/browse/STK-474 - @todo and NYI
239 *
240 * \note NYI - see &&&& - probably availble for POSIX, but not sure for windoze threads
241 * http://man7.org/linux/man-pages/man3/pthread_attr_setguardsize.3.html
242 * Perhaps for windows just add to end of stacksize
243 */
244 optional<size_t> fStackGuard;
245
246#if qStroika_Foundation_Common_Platform_Windows
247 optional<bool> fThrowInterruptExceptionInsideUserAPC;
248#endif
249 };
250
251 /**
252 * Return or Set the global default configuration for Thread object construction.
253 */
255 Configuration DefaultConfiguration (const optional<Configuration>& newConfiguration);
256
257 /**
258 * optional flag for constructing new threads
259 */
261 eAutoStart
262 };
263
264 /**
265 * Common::DefaultNames<> is defined for this enumeration.
266 */
267 enum class Status : uint8_t {
268 eNotYetRunning, // created, but start not yet called
269 eRunning, // in the context of the 'Run' method
270 eAborting, // Abort () called, but the thread still hasn't yet unwound
271 eCompleted, // run has terminated (possibly by exception, possibly normally, possibly because of Abort call)
272
273 Stroika_Define_Enum_Bounds (eNotYetRunning, eCompleted)
274 };
275
276 /**
277 *
278 * \note Common::DefaultNames<> supported
279 */
280 enum class Priority {
281 eLowest,
282 eBelowNormal,
283 eNormal,
284 eAboveNormal,
285 eHighest,
286
287 Stroika_Define_Enum_Bounds (eLowest, eHighest)
288 };
289
290 /**
291 *
292 */
293 struct ConfigurationStatus : Configuration {
294 /**
295 * Stack starts at base, and grows towards limit - could be up or down.
296 */
297 optional<const byte*> fStackBase;
298
299 /**
300 * @see fStackBase
301 */
302 optional<const byte*> fStackLimit;
303
304 /**
305 * @see fStackBase, fStackLimit
306 */
307 optional<const byte*> fCurrentStackAt;
308
309 /**
310 * Return current stack used, if available
311 *
312 * \note NYI
313 */
314 optional<size_t> GetStackUsed () const;
315
316 /**
317 * Return current stack available, if available
318 *
319 * \note NYI
320 */
321 optional<size_t> GetStackAvailable () const;
322 };
323
324 /**
325 * \brief Thread::Ptr is a (unsynchronized) smart pointer referencing an internally synchronized std::thread object (rep), with special feautres, including cancelation
326 *
327 * \note Since this is a smart pointer, the constness of the methods depends on whether they modify the smart pointer itself, not
328 * the underlying thread object.
329 *
330 * \see Thread::CleanupPtr
331 *
332 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety-For-Envelope-Letter-Internally-Synchronized">C++-Standard-Thread-Safety-For-Envelope-Letter-Internally-Synchronized</a>
333 */
334 class Ptr {
335 private:
336 class Rep_;
337
338 public:
339 /**
340 * \par Example Usage
341 * \code
342 * Thread::Ptr t = Thread::New ([r]() { r->Run (); }, Thread::eAutoStart, "Thread Name");
343 * Thread::Ptr t2 = t;
344 * \endcode
345 */
346 Ptr () = default;
347 Ptr (nullptr_t);
348 Ptr (const Ptr& src);
349 Ptr (Ptr&& src) noexcept;
350
351 protected:
352 Ptr (const shared_ptr<Rep_>& rep);
353
354 public:
355 /**
356 */
357 nonvirtual Ptr& operator= (const Ptr& rhs);
358 nonvirtual Ptr& operator= (Ptr&& rhs) noexcept;
359
360 public:
361 /**
362 * \brief Clear the pointer this Thread smart pointer refers to. This does nothing to affect the state of the underlying thread.
363 *
364 * \Ensure *this == nullptr
365 */
366 nonvirtual void reset () noexcept;
367
368 public:
369 /**
370 * Each thread has associated an std::function, which gets run by the thread. It can be accessed
371 * via GetFunction(), but is only settable in the thread constructor.
372 */
373 nonvirtual function<void ()> GetFunction () const;
374
375 public:
376 /**
377 * \note GetID () may return a default-constructed IDType if the thread is not running (has not been started, or has terminated)
378 */
379 nonvirtual IDType GetID () const;
380
381 public:
382 /**
383 * \note GetNativeHandle () may return a default-constructed NativeHandleType if the thread is not running (has not been started, or has terminated)
384 */
385 nonvirtual NativeHandleType GetNativeHandle () const noexcept;
386
387#if __cpp_lib_jthread >= 201911
388 public:
389 /**
390 */
391 nonvirtual stop_token GetStopToken () const;
392#endif
393
394 public:
395 /**
396 * For start method
397 */
399 eWaitUntilStarted
400 };
401
402 public:
403 /**
404 * \pre GetStatus () == Status::eNotYetRunning or Status::eAborting
405 * \pre never called before on this thread object
406 *
407 * Typically you won't call this directly, but instead pass the eStart parameter to the Thread constructor.
408 * But you can explicitly call if you prefer.
409 *
410 * A thread can only be started once. When it is constructed (without eStart) - it starts in the NotYetRunning state. And can
411 * only be started when its in that state.
412 *
413 * The zero argument Start overload returns, with the thread in any possible state.
414 * This function returns quickly, and the state of the thread may not have changed by the time it ru
415 * ensures when it returns the state is running, or completed, but cannot (yet) be aborted?? or null or not yet running
416 *
417 * The Start (WaitUntilStarted) overload waits for the thread to have started (or throws if it cannot start thread). Note the thread
418 * can still run to completion, or be aborted somewhere along the lines. So in this case:
419 * Ensure (s == Status::eRunning or s == Status::eAborting or s == Status::eCompleted );
420 */
421 nonvirtual void Start () const;
422 nonvirtual void Start (WaitUntilStarted) const;
423
424#if qStroika_Foundation_Common_Platform_Windows
425 public:
426 /**
427 * CalledInRepThreadAbortProc_ USED TO (until Stroika 2.0a234) - call CheckForThreadInterupption () in most cases. But that appeared to cause some trouble
428 * problably because of Windows library code calling an altertable function without being prepared for it to throw. So we adopted
429 * a safer apporach, and just follow all these alertable calls with CheckForInterruption().
430 *
431 * However, occasionally you use a library (like gsoap) that makes this difficult, so for those cases, enable this throw from APC feature.
432 *
433 * \note Get function CAN be called with *this == nullptr, but
434 * \pre if throwInterruptExceptionInsideUserAPC then *this != nullptr;
435 */
436 nonvirtual bool ThrowInterruptExceptionInsideUserAPC () const noexcept;
437 nonvirtual bool ThrowInterruptExceptionInsideUserAPC (optional<bool> throwInterruptExceptionInsideUserAPC);
438#endif
439
440 public:
441 /**
442 * \brief Abort gracefully shuts down and terminates the given thread (using cooperative multitasking).
443 *
444 * \note Since Stroika v3.0 (and C++20), this is accompished internally via std::stop_token.
445 *
446 * Cancelation works by setting a flag in that thread, which is checked at each 'cancelation point' (plus a little
447 * extra magic).
448 *
449 * This causes the given thread to throw an AbortException whenever it reaches one of these cancelation points
450 * (or if already at one such waitable cancelation point).
451 *
452 * This call is (generally) non-blocking (may block briefly for critical section to update status,
453 * but does NOT block until Stop successful). See AbortAndWaitUntilDone() to abort and wait for completion.
454 *
455 * This can be called on a thread object at any time (reps are internally syncrhonized), and in any state (except nullptr, which can only happen in the thread
456 * was created with nullptr/default CTOR and never assigned from Thread::New).
457 *
458 * \note This counts on Stroika's semi-cooperative multitasking (to be safe). This means if you call libraries that don't
459 * check for thread interruption, those threads may not BE interruptible during that region of code.
460 * @see Thread::GetThrowInterruptExceptionInsideUserAPC()
461 *
462 * \note It IS possible to have two DIFFERNT Ptr objects being called in different threads, one doing a Start ()
463 * and the other doing an Abort (); because of this, its allowed to call Start() in the 'aborted' state.
464 *
465 * \pre *this != nullptr
466 */
467 nonvirtual void Abort () const;
468
469 public:
470 /**
471 * \brief Wait for the pointed-to thread to be done. If the thread completed with an exception (other than thread abort exception)
472 * that exception will be re-thrown in the calling thread.
473 *
474 * This API is frequently preferred over WaitForDone () - because you frequently will do work in a thread which when failing - you want
475 * reported somehow. But this is not ALWAYS desirable - like when you have worker threads are just trying to clean up, and don't care that
476 * parts of it may have failed.
477 *
478 * JoinUntil (timeout + Time::GetTickCount ());
479 *
480 * @see WaitForDone ()
481 * @see ThrowIfDoneWithException ()
482 *
483 * \note ***Cancelation Point***
484 *
485 * \pre *this != nullptr
486 */
487 nonvirtual void Join (Time::DurationSeconds timeout = Time::kInfinity) const;
488
489 public:
490 /**
491 * \brief Wait for the pointed-to thread to be done. If the thread completed with an exception (other than thread abort exception)
492 * that exception will be re-thrown in the calling thread.
493 *
494 * This API is frequently preferred over WaitForDone () - because you frequently will do work in a thread which when failing - you want
495 * reported somehow. But this is not ALWAYS desirable - like when you have worker threads are just trying to clean up, and don't care that
496 * parts of it may have failed.
497 *
498 * WaitForDoneUntil () followed up ThrowIfDoneWithException ()
499 *
500 * \note Considered using ThrowIfDoneWithException () always in WaitForDone()
501 * or make optional if existing WAIT API throws child exceptions. Maybe parameter in construction
502 * of the thread?
503 *
504 * Decided against always re-throwing because sometimes you just don't care for a given thread what sort of errors
505 * it had (maybe cuz you've given up on the larger task).
506 *
507 * Decided against encoding that choice in the Thread::New () function (making it a property) and then always doing in WaitForDone () - because
508 * then the the choice would be far away from where the waiting is done - and that Waiting - really needs to be setup to KNOW its likely
509 * to get an exception. So that seemed the wrong place.
510 *
511 * Considered making this just an overload of WaitForDone () - with an extra param - reThrow - and that's really close to what I ended up
512 * with. But overloading would force me to pick a default, which would cause a struggle between backward compatabilitiy and what
513 * I think is the more common case. Or maybe there is no clearly more common case. This name seems fine.
514 *
515 * \note Possible aliases WaitAndThrowAnyChildThreadExceptions, WaitForDoneUntilAndPropagateExceptions ()
516 *
517 * @see WaitForDoneUntil ()
518 * @see ThrowIfDoneWithException ()
519 *
520 * \note ***Cancelation Point***
521 *
522 * \pre *this != nullptr
523 */
524 nonvirtual void JoinUntil (Time::TimePointSeconds timeoutAt) const;
525
526 public:
527 /**
528 * Wait until thread is done (use Abort to request termination) - throws if timeout
529 * Note that its legal to call WaitForDone on a thread in any state (Some may just
530 * have no effect - return quickly).
531 *
532 * @see WaitForDoneUntil (), @see Join
533 *
534 * \note ***Cancelation Point***
535 *
536 * \pre *this != nullptr
537 */
538 nonvirtual void WaitForDone (Time::DurationSeconds timeout = Time::kInfinity) const;
539
540 public:
541 /**
542 * Wait until thread is done (use Abort to request termination) - throws if timeout
543 * Note that its legal to call WaitForDoneUntil on a thread in any state.
544 * Some may just have no effect.
545 *
546 * @see WaitForDone (), @see Join
547 *
548 * \note This does a tiny bit more than waiting for the done state to be set - it also
549 * 'joins' (frees memory for) underlying thread if still allocated. This should not be visible/noticed
550 * except for in a debugger or #if qStroika_Foundation_Execution_Thread_SupportThreadStatistics
551 *
552 * \note ***Cancelation Point***
553 *
554 * \pre *this != nullptr
555 */
556 nonvirtual void WaitForDoneUntil (Time::TimePointSeconds timeoutAt) const;
557
558 public:
559 /**
560 * Wait until thread is done (use Abort to request termination) or timeoutAt expires
561 *
562 * Returns: true if thread done, and false if timeout
563 *
564 * Note that its legal to call WaitForDoneUntilQuietly on a thread in any state - including nullptr.
565 * Some may just have no effect.
566 *
567 * \note This does a tiny bit more than waiting for the done state to be set - it also
568 * 'joins' (frees memory for) underlying thread if still allocated. This should not be visible/noticed
569 * except for in a debugger or #if qStroika_Foundation_Execution_Thread_SupportThreadStatistics
570 *
571 * \note ***Cancelation Point***
572 *
573 * \pre *this != nullptr
574 */
575 nonvirtual bool WaitForDoneUntilQuietly (Time::TimePointSeconds timeoutAt) const;
576
577 public:
578 /**
579 * \brief Abort () the thread, and then WaitForDone () - but if doesn't finish fast enough, send extra aborts (aka AbortAndWaitForDoneUntil (timeout + GetTickCount))
580 *
581 * \note This frequently (and nearly always in a destructor) - should be preceded by:
582 * \code
583 * Execution::Thread::SuppressInterruptionInContext suppressInterruption; // critical to prohibit this thread from interruption until its killed owned threads
584 * \endcode
585 *
586 * @see AbortAndWaitForDoneUntil ()
587 *
588 * \note ***Cancelation Point***
589 *
590 * \pre *this != nullptr
591 */
592 nonvirtual void AbortAndWaitForDone (Time::DurationSeconds timeout = Time::kInfinity) const;
593
594 public:
595 /**
596 * \brief Abort () the thread, and then WaitForDone () - but if doesn't finish fast enough, send extra aborts
597 *
598 * \note Note that its legal to call AbortAndWaitForDone on a thread in any state.
599 * Some may just have no effect
600 *
601 * An example of when this is useful is if you have a thread (performing some operation on
602 * behalf of an object - with data pointers to that object)
603 * and must stop the thread (its no longer useful) - but must assure its done before you
604 * destroy the rest of the data...)
605 * As for example in FileUtils - DirectoryWatcher...
606 *
607 * throws if timeout
608 *
609 * \note This frequently (and nearly always in a destructor) - should be preceded by:
610 * \code
611 * Execution::Thread::SuppressInterruptionInContext suppressInterruption; // critical to prohibit this thread from interruption until its killed owned threads
612 * \endcode
613 *
614 * \note ***Cancelation Point***
615 *
616 * @see Abort ()
617 * @see WaitForDoneUntil ()
618 * @see AbortAndWaitForDone ()
619 *
620 * \pre *this != nullptr
621 */
622 nonvirtual void AbortAndWaitForDoneUntil (Time::TimePointSeconds timeoutAt) const;
623
624 public:
625 /**
626 * If the thread is Done() - and completed with an exception (other than interrupt),
627 * this throws that exception, allowing an exception thrown inside a thread,
628 * to be propagated across threads.
629 *
630 * \note This function intentionally omits InterruptException and AbortException from
631 * this rule, so that if you abort or interrupt a thread and then call this method,
632 * it will not rethrow.
633 *
634 * The reason for this choice is that the interrupt/abort are usually generated externally
635 * and the intent of this method is to pass information back from the thread to the caller.
636 */
637 nonvirtual void ThrowIfDoneWithException () const;
638
639#if qStroika_Foundation_Common_Platform_Windows
640 public:
641 /**
642 * Look pumping messages until either time2Pump is exceeded or the thread completes.
643 * Its NOT an error if the timeout is exceeded.
644 *
645 * throws if timeout
646 *
647 * @see WaitForDoneUntil ()
648 *
649 * \note ***Cancelation Point***
650 *
651 * \pre *this != nullptr
652 */
653 nonvirtual void WaitForDoneWhilePumpingMessages (Time::DurationSeconds timeout = Time::kInfinity) const;
654#endif
655
656 public:
657 /**
658 * This is a portable wrapper on setting thread priorities. It has fewer knobs than direct or low level
659 * APIs. You can always directly call low-level native APIs using GetNativeHandle().
660 *
661 * \note - no GetPriority API, cuz cannot do something vaguely like that portably. For one thing, priority
662 * is more complex than a single number (like this argument) at runtime for reading on Linux.
663 */
664 nonvirtual void SetThreadPriority (Priority priority = Priority::eNormal) const;
665
666 public:
667 /**
668 * Each Thread object has an associated state. Since this can be accessed from one thread while things
669 * in another thread, by the time the answer is returned, the value may have changed.
670 *
671 * But only certain transitions are legal. Status::eNull is the starting state for SOME Thread constructors (no arg).
672 * Nothing transitions back to the Status:eNull state. From there when you specify a std::function<> to run,
673 * then you transition to Status::eNotYetRunning.
674 *
675 * From eNotYetRunning, you can transition to eRunning with Start () (or the starting thread CTOR). Or you can transition from
676 * eNotYetRunning to eAborting, if you call Abort() before Start().
677 *
678 * From eRunning (or eNotYetRunning) you can transition to eAborting or eCompleted (or from eAborting to eCompleted).
679 *
680 * A thread object can never transition back (by this I mean the underlying pointed to rep - the container of
681 * course can transition back by being assigned another ThreadRep).
682 *
683 * \pre *this != nullptr
684 *
685 * \note - Calling GetStatus () is generally not a good idea, except for debugging purposes. Generally, you will
686 * want to call WaitForDone (), and perhaps Abort, or AbortAndWaitForDone (). GetStatus () gives you a clue
687 * what the thread was doing, but by the time you look it could have changed.
688 */
689 nonvirtual Status GetStatus () const noexcept;
690
691 public:
692 /**
693 * Return true iff WaitForDone () would return immediately;
694 *
695 * \pre not == nullptr
696 *
697 * This will return true iff GetStatus() would return eCompleted.
698 *
699 * Note - some internal traces of the thread object may still be running at this point, but its safe to call join at this point without significant blockage.
700 */
701 nonvirtual bool IsDone () const;
702
703 public:
704 /**
705 * Thread name does NOT need to be unique and defaults to '', but can be used on advisory
706 * basis for debugging. Also - setting the thread name, and then getting it back, may not
707 * produce the same result. Some OSes may munge the name to make it unique, or conform
708 * to some naming convention.
709 *
710 * These names should not be counted on for program logic.
711 *
712 * Thread names appear frequently in debug trace messages.
713 */
714 nonvirtual Characters::String GetThreadName () const;
715
716 public:
717 /**
718 * \pre GetStatus () != Status::eNull
719 *
720 * @see GetThreadName ();
721 */
722 nonvirtual void SetThreadName (const Characters::String& threadName) const;
723
724 public:
725 /**
726 * Return a snapshot of the current stack settings - configured - and dynamic. Much/most of this
727 * may not be available on your system.
728 *
729 * \note @todo - IMPLEMENT ON SOME SYSTEM ;-) Not sure if/where we can do this. Tricky...
730 * \note NYI - see http://stroika-bugs.sophists.com/browse/STK-475
731 */
732 nonvirtual ConfigurationStatus GetConfigurationStatus () const;
733
734 public:
735 /**
736 * @see Characters::ToString ()
737 */
738 nonvirtual Characters::String ToString () const;
739
740 public:
741 /**
742 */
743 nonvirtual bool operator== (const Ptr& rhs) const;
744 nonvirtual bool operator== (nullptr_t) const;
745
746 public:
747 /**
748 */
749 nonvirtual strong_ordering operator<=> (const Ptr& rhs) const;
750 nonvirtual strong_ordering operator<=> (nullptr_t) const;
751
752 public:
753 /**
754 * \brief return true iff *this != nullptr
755 */
756 nonvirtual explicit operator bool () const;
757
758 private:
759 shared_ptr<Rep_> fRep_;
760 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
761#if qCompilerAndStdLib_thread_local_static_inline_twice_Buggy
762 static weak_ptr<Rep_>& sCurrentThreadRep_BWA_ ()
763 {
764 static thread_local weak_ptr<Rep_> sCurrentThreadRep_;
765 return sCurrentThreadRep_;
766 }
767#else
768 static inline thread_local weak_ptr<Rep_> sCurrentThreadRep_;
769#endif
770
771 private:
772 friend Ptr New (const function<void ()>& fun2CallOnce, const optional<Characters::String>& name, const optional<Configuration>& configuration);
773 friend Ptr GetCurrent ();
775 friend void CheckForInterruption ();
776 };
777
778 /**
779 * Handy wrapper around a Thread::Ptr, when you want to assure the thread is terminated before the CleanupPtr goes out of scope.
780 */
781 class CleanupPtr : public Ptr {
782 public:
783 /**
784 */
785 enum class AbortFlag {
786 eAbortBeforeWaiting,
787 eDirectlyWait
788 };
789 using AbortFlag::eAbortBeforeWaiting;
790 using AbortFlag::eDirectlyWait;
791
792 public:
793 /**
794 * \brief in destructor, wait for the thread to terminate (optionally aborting it first - depending on CleahupPtr arg/flag)
795 *
796 * \note it is OK to pass a nullptr, or to otherwise stop/abort the thread. This class wraps safe checking around the thread ptr to make sure
797 * it gets cleaned up.
798 */
799 CleanupPtr (const CleanupPtr&) = delete;
800 CleanupPtr (AbortFlag abortFlag, Ptr threadPtr = nullptr);
801
802 public:
803 ~CleanupPtr ();
804
805 public:
806 /**
807 * Assigning a new Thread::Ptr object just replaces the thread that will be 'cleaned up' in the
808 * CleanupPtr destructor. It doesn't force the previous thread to be terminated.
809 */
810 nonvirtual CleanupPtr& operator= (const Ptr&);
811 nonvirtual CleanupPtr& operator= (const CleanupPtr&) = delete;
812
813 private:
814 bool fAbort_{false};
815 };
816
817 /**
818 */
819 class AbortException : public Exception<> {
820 public:
821 AbortException ();
822
823 public:
824 /*
825 * Handy constant you can use to avoid construction.
826 *
827 * Statically allocate because:
828 * o Performance
829 * o Only legal to throw these while main active (so safe to use in that context)
830 * o Avoids issue with re-throwing while constructing one
831 */
832 static const AbortException kThe;
833 };
834 inline const AbortException AbortException::kThe;
835
836 using InterruptException [[deprecated ("Since Stroika v3.0d4 - use AbortException")]] = AbortException;
837
838 /**
839 * Thread IDs tend to be long and not easy to read in trace output. This utility class just maps these long
840 * ids to a short index. Again - ONLY for easier / brevity in logging. But a common registry is maintained here
841 * to allow all the logging across Stroika to use the same shortened IDs.
842 *
843 * Note you can only reference the singleton sThe. This can be referenced before main, or after main safely,
844 * but in those cases, there can be no threads, so it just returns zero (GetIndex).
845 *
846 * NOTE - this class is slightly queer, in that it guarantees behavior of one of its methods BEFORE its
847 * constructed and AFTER its been destroyed. This cannot be 100% true in general and might cause some problems
848 * with sanitizers and the like. But I think this path will generally work and certainly tries to give reasonable
849 * answers when called outside its lifetime (and should work due to only having a single singleton instance).
850 *
851 * \note \em Thread-Safety <a href="Thread-Safety.md#Internally-Synchronized-Thread-Safety">Internally-Synchronized-Thread-Safety</a>
852 */
854 protected:
855 IndexRegistrar (const IndexRegistrar&) = delete;
857
858 public:
860
861 public:
862 nonvirtual IndexRegistrar& operator= (const IndexRegistrar&) = delete;
863
864 public:
865 /**
866 */
867 nonvirtual unsigned int GetIndex (const IDType& threadID, bool* wasNew = nullptr);
868
869 public:
870 /**
871 */
872 static IndexRegistrar sThe;
873
874 private:
875 bool fInitialized_{false};
876 mutex fMutex_; // for read/update the fShownThreadIDs_ map
877 map<IDType, unsigned int> fShownThreadIDs_; // use std::map instead of Stroika to avoid module deadly embrace
878 };
879 inline IndexRegistrar IndexRegistrar::sThe;
880
881 /**
882 * This object - while in existence, blocks delivery of all Thread::AbortException's
883 * (for this thread in which its instantiated). This blocking nest (so if you have two of them in one thread, only when the last
884 * one is destroyed does the block on Interruption be removed).
885 *
886 * This is used to prevent a second abort request coming in to a thread already in the process of shutting down, which
887 * might cause a second, or incomplete cleanup.
888 *
889 * Note - this does NOT prevent the delivery of Windows APC messages, nor POSIX interrupt signals. It just prevents that
890 * from doing anything (other than maybe an EINTR return).
891 *
892 * It might be NICE to have the DTOR be a cancelation point, but that would violate the rule that you cannot throw
893 * from a destructor.
894 *
895 * Any blocked Interrupt Exceptions will wait til the next cancelation point to be invoked (so call
896 * CheckForInterruption to force that). The destructor of this suppress (even when count hits zero)
897 * will not throw.
898 */
906
907 /**
908 * No arg- constructor is available for use in applications like thread pools. Also, a variety
909 * of cases, its handy to declare a Thread data member (and init in CTOR), but not
910 * specify what gets run until later.
911 *
912 * After this call, GetStatus () returns Status::eNull
913 *
914 * fun2CallOnce is called precisely once by this thread CTOR, but called in
915 * another thread with the arg 'arg'.
916 *
917 * \note about the 'configuration' parameter. If missing (or parts missing) - the whole are parts from from
918 * the static GetDefaultConfiguration () function. If defaults are missing there too, the OS / system defaults
919 * are relied upon.
920 *
921 * It's not expected one would need to use this often, but when you need it you need it early - before the thread has
922 * been constructed (generally) - or at least before started (sucks swapping stacks out on a running thread ;-))
923 *
924 * \note Unlike std::thread, a Stroika Thread is not started automatically (unless you pass eAutoStart as a constructor argument),
925 * and it can run in the background after the Thread has gone out of scope (std::thread you can do this but must call detach).
926 *
927 * \pre Debug::AppearsDuringMainLifetime() at all points during the threads lifetime. It must be stopped
928 * before Debug::AppearsDuringMainLifetime() becomes untrue. This is somewhat checked by the Stroika
929 * thread infrastructure, but may not be fully reliably asserted (see AllThreadsDeadDetector_)
930 *
931 * \par Example Usage
932 * \code
933 * Thread::New ([r]() { r->Run (); }, Thread::eAutoStart); // runs arg to completion then thread destroyed. New returns once thread created
934 * \endcode
935 *
936 * \par Example Usage
937 * \code
938 * Thread::Ptr t = Thread::New ([r]() { r->Run (); }, Thread::eAutoStart, "Thread Name");
939 * \endcode
940 *
941 * \par Example Usage
942 * \code
943 * Thread::Ptr t = Thread::New ([r]() { r->Run (); });
944 * t.Start ();
945 * t.WaitForDone ();
946 * \endcode
947 */
948 Ptr New (const function<void ()>& fun2CallOnce, const optional<Characters::String>& name, const optional<Configuration>& configuration);
949 Ptr New (const function<void ()>& fun2CallOnce, const Characters::String& name, const optional<Configuration>& configuration = nullopt);
950 Ptr New (const function<void ()>& fun2CallOnce, const optional<Configuration>& configuration = nullopt);
951 Ptr New (const function<void ()>& fun2CallOnce, AutoStartFlag, const optional<Characters::String>& name,
952 const optional<Configuration>& configuration);
953 Ptr New (const function<void ()>& fun2CallOnce, AutoStartFlag, const Characters::String& name,
954 const optional<Configuration>& configuration = nullopt);
955 Ptr New (const function<void ()>& fun2CallOnce, AutoStartFlag, const optional<Configuration>& configuration = nullopt);
956
957 /**
958 * \pre foreach Thread t: t.GetStatus () == Status::eNotYetRunning
959 */
960 void Start (const Traversal::Iterable<Ptr>& threads);
961
962 /**
963 * \brief foreach Thread t: t.Abort ()
964 *
965 * \pre foreach Thread t: t != nullptr
966 *
967 * \see Thread::Ptr::Abort
968 */
969 void Abort (const Traversal::Iterable<Ptr>& threads);
970
971 /**
972 * \note ***Cancelation Point***
973 *
974 * \pre foreach Thread t: t != nullptr
975 */
976 void WaitForDone (const Traversal::Iterable<Ptr>& threads, Time::DurationSeconds timeout = Time::kInfinity);
977
978 /**
979 * \note ***Cancelation Point***
980 *
981 * \pre foreach Thread t: t != nullptr
982 */
984
985 /**
986 * \brief - shorthand for AbortAndWaitForDoneUntil (Time::GetTickCount () + timeout)
987 *
988 * \note ***Cancelation Point***
989 *
990 * @see Thread::Ptr::AbortAndWaitForDone
991 *
992 * @see Thread::AbortAndWaitForDoneUntil
993 *
994 * \note This frequently (and nearly always in a destructor) - should be preceded by:
995 * \code
996 * Execution::Thread::SuppressInterruptionInContext suppressInterruption; // critical to prohibit this thread from interruption until its killed owned threads
997 * \endcode
998 *
999 * \pre foreach Thread t: t != nullptr
1000 */
1001 void AbortAndWaitForDone (const Traversal::Iterable<Ptr>& threads, Time::DurationSeconds timeout = Time::kInfinity);
1002
1003 /**
1004 * \note ***Cancelation Point***
1005 *
1006 * @see Thread::Ptr::AbortAndWaitForDoneUntil
1007 *
1008 * \note This frequently (and nearly always in a destructor) - should be preceded by:
1009 * \code
1010 * Execution::Thread::SuppressInterruptionInContext suppressInterruption; // critical to prohibit this thread from interruption until its killed owned threads
1011 * \endcode
1012 *
1013 * \pre foreach Thread t: t != nullptr
1014 */
1016
1017 /**
1018 * Generally should not be reported. It's just to help force a thread to shut itself down
1019 */
1020 class AbortException;
1021
1023
1024#if qStroika_Foundation_Execution_Thread_SupportThreadStatistics
1025 /**
1026 */
1027 struct Statistics {
1028 /**
1029 * These are the thread objects in the status 'running'. It doesn't count ones that exist,
1030 * or Thread objects (which could be null or completed)
1031 */
1032 Traversal::Iterable<IDType> fRunningThreads;
1033 };
1034
1035 /**
1036 * This does not return statistics about this thread (its a static method) - but about all thread allocations (through
1037 * the Stroika thread API).
1038 */
1039 Statistics GetStatistics ();
1040#endif
1041
1042#if qStroika_Foundation_Common_Platform_POSIX
1043 /**
1044 * Unsafe to change this while threads running - at least if you could be interupting threads during this time.
1045 * If argument given, this resets the signalNumber.
1046 * Either way, this returns the previous value.
1047 */
1048 SignalID SignalUsedForThreadInterrupt () noexcept;
1049 SignalID SignalUsedForThreadInterrupt (optional<SignalID> signalNumber);
1050#endif
1051
1052 struct FormatThreadInfo {
1053 bool fIncludeLeadingZeros{false};
1054 };
1055
1056 /**
1057 * Represent the thread ID for display - typically as an integer.
1058 *
1059 * \note this function is NOT a cancelation point
1060 *
1061 * \note this returns an ASCII string (not using String class library) so easier to use from code expecting no cancelation
1062 *
1063 * @see Characters::ToString (Thread::IDType threadID)
1064 */
1065 wstring FormatThreadID (Thread::IDType threadID, const FormatThreadInfo& formatInfo = {});
1066 string FormatThreadID_A (Thread::IDType threadID, const FormatThreadInfo& formatInfo = {});
1067
1068 /**
1069 */
1070 IDType GetCurrentThreadID () noexcept;
1071
1072 /**
1073 * If the current (calling) thread is a 'Stroika thread' - that thread Ptr is returned. If the current thread is NOT a stroika thread (e.g. the main thread)
1074 * this will return a nullptr.
1075 *
1076 * \note SEE http://stroika-bugs.sophists.com/browse/STK-994 - for the idea of creating a special Ptr - just for the main thread. But really
1077 * no reason I can see --LGP 2023-10-18
1078 */
1079 Ptr GetCurrent ();
1080
1081#if __cpp_lib_jthread >= 201911
1082 /**
1083 */
1084 optional<stop_token> GetCurrentThreadStopToken ();
1085#endif
1086
1087 /**
1088 * Returns true iff it is potentially useful to call CheckForInterruption.
1089 */
1091
1092 /**
1093 * Our thread interruption (and abort) mechanism only throws at certain 'signalable' (alertable/cancelable)
1094 * spots in the code - like sleeps, most reads, etc.
1095 * This function will also trigger a throw if called inside a thread which is being aborted.
1096 *
1097 * Any call to this routine is a 'cancelation point'.
1098 *
1099 * \note ***Cancelation Point***
1100 *
1101 * \note This name is somewhat historical, but still reasonable. But now might be better called CheckForThreadAbort, since thats all it does now.
1102 */
1103 void CheckForInterruption ();
1104
1105 /*
1106 * Avoid interference with Windows SDK headers. I hate needless C macros (with short, common names)
1107 */
1108#ifdef Yield
1109#undef Yield
1110#endif
1111
1112 /**
1113 * \brief calls CheckForInterruption, and std::this_thread::yield ()
1114 *
1115 * \note ***Cancelation Point***
1116 * To avoid cancelation point, directly call std::this_thread::yield ()
1117 */
1118 dont_inline void Yield ();
1119
1120 };
1121
1122}
1123
1124/*
1125 ********************************************************************************
1126 ***************************** Implementation Details ***************************
1127 ********************************************************************************
1128 */
1129#include "Thread.inl"
1130
1131#endif /*_Stroika_Foundation_Execution_Thread_h_*/
#define Stroika_Define_Enum_Bounds(FIRST_ITEM, LAST_ITEM)
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Definition Realtime.h:82
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
Exception<> is a replacement (subclass) for any std c++ exception class (e.g. the default 'std::excep...
Definition Exceptions.h:157
CleanupPtr(const CleanupPtr &)=delete
in destructor, wait for the thread to terminate (optionally aborting it first - depending on CleahupP...
nonvirtual CleanupPtr & operator=(const Ptr &)
Definition Thread.inl:307
Thread::Ptr is a (unsynchronized) smart pointer referencing an internally synchronized std::thread ob...
Definition Thread.h:334
nonvirtual ConfigurationStatus GetConfigurationStatus() const
friend Ptr New(const function< void()> &fun2CallOnce, const optional< Characters::String > &name, const optional< Configuration > &configuration)
nonvirtual void SetThreadName(const Characters::String &threadName) const
Definition Thread.cpp:710
nonvirtual void Join(Time::DurationSeconds timeout=Time::kInfinity) const
Wait for the pointed-to thread to be done. If the thread completed with an exception (other than thre...
Definition Thread.inl:276
nonvirtual void reset() noexcept
Clear the pointer this Thread smart pointer refers to. This does nothing to affect the state of the u...
Definition Thread.inl:194
nonvirtual void WaitForDoneUntil(Time::TimePointSeconds timeoutAt) const
Definition Thread.cpp:871
nonvirtual void WaitForDone(Time::DurationSeconds timeout=Time::kInfinity) const
Definition Thread.inl:286
nonvirtual void Abort() const
Abort gracefully shuts down and terminates the given thread (using cooperative multitasking).
Definition Thread.cpp:809
nonvirtual bool WaitForDoneUntilQuietly(Time::TimePointSeconds timeoutAt) const
Definition Thread.cpp:879
nonvirtual void JoinUntil(Time::TimePointSeconds timeoutAt) const
Wait for the pointed-to thread to be done. If the thread completed with an exception (other than thre...
Definition Thread.inl:280
nonvirtual void ThrowIfDoneWithException() const
Definition Thread.cpp:859
nonvirtual function< void()> GetFunction() const
Definition Thread.inl:199
nonvirtual NativeHandleType GetNativeHandle() const noexcept
Definition Thread.inl:178
nonvirtual Characters::String ToString() const
Definition Thread.cpp:723
nonvirtual IDType GetID() const
Definition DOM.inl:157
nonvirtual void AbortAndWaitForDone(Time::DurationSeconds timeout=Time::kInfinity) const
Abort () the thread, and then WaitForDone () - but if doesn't finish fast enough, send extra aborts (...
Definition Thread.inl:291
nonvirtual void AbortAndWaitForDoneUntil(Time::TimePointSeconds timeoutAt) const
Abort () the thread, and then WaitForDone () - but if doesn't finish fast enough, send extra aborts.
Definition Thread.cpp:848
nonvirtual Characters::String GetThreadName() const
Definition Thread.cpp:704
nonvirtual Status GetStatus() const noexcept
Definition Thread.inl:255
nonvirtual void SetThreadPriority(Priority priority=Priority::eNormal) const
Definition Thread.cpp:689
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:237
Ptr New(const function< void()> &fun2CallOnce, const optional< Characters::String > &name, const optional< Configuration > &configuration)
Definition Thread.cpp:955
void AbortAndWaitForDoneUntil(const Traversal::Iterable< Ptr > &threads, Time::TimePointSeconds timeoutAt)
Definition Thread.cpp:995
thread::native_handle_type NativeHandleType
Definition Thread.h:222
void Start(const Traversal::Iterable< Ptr > &threads)
Definition Thread.inl:347
wstring FormatThreadID(Thread::IDType threadID, const FormatThreadInfo &formatInfo={})
Definition Thread.cpp:1052
void WaitForDone(const Traversal::Iterable< Ptr > &threads, Time::DurationSeconds timeout=Time::kInfinity)
Definition Thread.inl:351
dont_inline void Yield()
calls CheckForInterruption, and std::this_thread::yield ()
Definition Thread.cpp:1180
Configuration DefaultConfiguration() noexcept
Definition Thread.cpp:965
void WaitForDoneUntil(const Traversal::Iterable< Ptr > &threads, Time::TimePointSeconds timeoutAt)
Definition Thread.cpp:1008
void Abort(const Traversal::Iterable< Ptr > &threads)
foreach Thread t: t.Abort ()
Definition Thread.cpp:987
void AbortAndWaitForDone(const Traversal::Iterable< Ptr > &threads, Time::DurationSeconds timeout=Time::kInfinity)
shorthand for AbortAndWaitForDoneUntil (Time::GetTickCount () + timeout)
Definition Thread.inl:343
EXPERIMENTAL SUPPORT FOR THREAD STACK (and maybe other) settings.
Definition Thread.h:231