ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
threadpool.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_threadmodel of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under #"mainpage_license".
7//==================================================================================================
8ALIB_EXPORT namespace alib {
9
10/// This is the namespace of \alibmod <b>"ThreadModel"</b>. Please refer to the
11/// #"alib_mod_threadmodel;Programmer's Manual" of this module for information
12/// about how the types found in this namespace are used.
13namespace threadmodel {
14
15//==================================================================================================
16/// Instances of this thread-class are created by #"ThreadPool"s.
17/// Applications may extend this class and override the method #"PrepareJob".
18//==================================================================================================
19struct PoolWorker : protected Thread {
20 #if !DOXYGEN
21 friend class ThreadPool;
22 #endif
23 ThreadPool& threadPool; ///< The pool that this instance belongs to.
24
25#if ALIB_STRINGS
26 String64 nameBuffer; ///< Buffer to store the thread name given with construction.
27
28 /// Constructor.
29 /// @param pThreadPool The pool that constructed us.
30 /// @param threadName The name of this thread (for logging and diagnosis)
31 PoolWorker(ThreadPool& pThreadPool, const character* threadName )
32 : Thread(threadName)
33 , threadPool(pThreadPool)
34 , nameBuffer(threadName)
35 { SetName(nameBuffer); } // fix the name to local pointer
36#else
38 : Thread("Poolworker")
39 , threadPool(ptp)
40 {}
41#endif
42
43 /// This default implementation does nothing. Derived types may dynamically cast the
44 /// parameter \p{job} to a known custom type and, for example, attach custom data found in
45 /// a derived version of this class.
46 ///@param job The job to prepare.
47 virtual void PrepareJob(Job* job) { (void) job; }
48
49 /// Implementation of #"Thread::Run;*". Retrieves jobs from the pool, invokes
50 /// #"PrepareJob", and then calls #"Job::Do;*".
51 void Run() override;
52
53}; // class PoolWorker
54
55//==================================================================================================
56/// This class provides a configurable and scalable thread pooling mechanism for managing
57/// concurrent job execution.
58/// It supports fix-sized or dynamically resizing thread pools to balance workload and optimize
59/// resource usage, along with several key methods to schedule, manage, and monitor job execution.
60///
61/// ### Key Features
62/// 1. <b>%Thread Pool Management</b>:<br>
63/// - Supports fixed-size and dynamically resizable thread pools.
64/// - Dynamic resizing is handled through customizable parameters found in the struct
65/// #"ThreadPool::ResizeStrategy".
66/// - Automatically adjusts the number of threads based on workload.
67///
68/// 2. <b>%Jobs</b>:<br>
69/// The worker-threads managed by the pool are processing #"Job" objects,
70/// which<br>
71/// a) Carry the data needed for processing, and<br>
72/// b) Optionally provide synchronization mechanics that allow a caller to wait until
73/// a job was processed or periodically test for completion.
74///
75/// Allocation and life-cycle management of jobs is efficiently implemented leveraging
76/// the mechanics provided by the module \alib_monomem.
77///
78/// 3. <b>Synchronization and %Job-Cleanup</b>:<br>
79/// Provides #"ThreadPool::Sync;a method to synchronize" all worker threads
80/// to ensure that processing continues only after a certain set of jobs has been executed.
81/// <br><br>
82///
83/// 4. <b>Worker Management and Monitoring</b>:<br>
84/// - Supports querying idle worker status and actively running threads.
85/// - Debugging options to analyze job types and execution states.
86///
87/// @see Chapter #"alib_thrmod_threadpool" of this module's Programmer's Manual
88/// provides a quick source code sample that demonstrates the use this class.
89//==================================================================================================
90class ThreadPool : protected TCondition<ThreadPool>
91#if ALIB_DEBUG_CRITICAL_SECTIONS
93#endif
94
95{
96 #if !DOXYGEN
97 friend struct PoolWorker;
98 friend struct threads::TCondition<ThreadPool>;
99 #endif
100
101 public:
102 /// The set of management parameters that determine how a thread pool balances the number
103 /// of worker threads.
105 {
106 #if !DOXYGEN
107 friend class ThreadPool;
108 #endif
109
110 /// The modes, fixed or automatic.
111 enum class Modes
112 {
113 /// The number of threads is fixed.
115
116 /// The number of threads is increased when the load increases and
117 /// decreased when the load decreases.
119 };
120
121 /// The mode of operation.
123
124 /// If #".Mode" equals \b Fixed, this is used and all other parameters are ignored.
125 /// If #".Mode" equals \b Auto, this field gives the maximum number of workers that are
126 /// run in parallel.<br>
128
129 /// The minimum number of threads to keep alive.
130 int WorkersMin = 0;
131
132 /// A threshold in percent that determines at which overload factor the number of threads
133 /// is increased.
134 /// Defaults to \c 300%. For example, this means if the pool currently holds 10 threads,
135 /// then new threads are created when the load increases to \c 30 unprocess jobs.
137
138 /// A threshold in percent that determines at which underload factor the number of threads
139 /// are decreased.
140 /// Defaults to \c 50%.
141 /// For example, \c 30% this means that if 70% of the threads are idle the number of
142 /// threads is decreased.
144
145 /// The duration of that the pool has to be overloaded before an increase of threads
146 /// starts.
147 /// Defaults to zero time interval.
148 Ticks::Duration IncreaseSchedule = Ticks::Duration::FromAbsoluteMilliseconds(0);
149
150 /// The duration of that the pool has to be underloaded before a decrease of threads starts.
151 /// Defaults to 500ms.
152 Ticks::Duration DecreaseSchedule = Ticks::Duration::FromAbsoluteMilliseconds(500);
153
154 protected:
155
156 /// Calculates the target size, depending on the parameters set in this struct and
157 /// the actual values passed.
158 /// @param currentWorkers The number of threads currently in the pool.
159 /// @param idleWorkers The size of the subset of threads currently idle.
160 /// @param load The number of jobs currently queued.
161 /// @param lastChangeTime Time point of last increase or decrease.
162 /// @return The new target size.
163 inline
164 int GetSize( int currentWorkers , int idleWorkers, int load,
165 Ticks& lastChangeTime ) {
166 int target= currentWorkers;
167
168 // fixed mode? -> nothing to do
169 if (Mode == Modes::Fixed)
170 { target= WorkersMax; }
171
172 // check bounds
173 else if( target < WorkersMin ) { target= WorkersMin; }
174 else if( target > WorkersMax ) { target= WorkersMax; }
175
176 // increase?
177 else if( lastChangeTime.Age() >= IncreaseSchedule
178 && (load >= (currentWorkers * IncreaseThreshold / 100) ) )
179 { target = (std::min)(WorkersMax, currentWorkers + 1); }
180
181 // decrease?
182 else if( lastChangeTime.Age() >= DecreaseSchedule
183 && (currentWorkers - idleWorkers) <= (currentWorkers * DecreaseThreshold / 100) ) {
184 target = (std::max)(WorkersMin, currentWorkers - 1);
185 if ( target == 0 && load > 0)
186 target= 1;
187 }
188
189 // that's it
190 if (target != currentWorkers)
191 lastChangeTime.Reset();
192 return target;
193 }
194 };
195
196
197 protected:
198 /// Mono allocator. Used for jobs and by PoolWorkers.
200
201 /// Pool allocator. Used for job objects.
203
204 /// The list of worker threads.
206
207 /// The counted number of currently of workers.
209
210 /// The counted number of currently idle workers.
211 int ctdIdle =0;
212
213 /// The point in time of the last change of thread size.
215
216 /// A number that is increased with the creation of new workers and added to their
217 /// #"Thread::GetName;thread name".
219
220 #if ALIB_DEBUG
221 /// Entry in the field #"DbgKnownJobs".
223 {
224 const std::type_info* TID; ///< The job type.
225 size_t JobSize; ///< The size of the job object.
226 size_t Usage; ///< Counter of scheduled jobs of this type.
227 };
228
229 /// Serves as template parameter \p{TValueDescriptor} of field #"DbgKnownJobs".
231 const std::type_info* >
232 {
233 /// Mandatory function to implement.
234 /// @param entry The table entry to extract the key from.
235 /// @return The key portion of the given \p{entry}.
236 const std::type_info* Key(DbgKnownJobsEntry& entry) const { return entry.TID; }
237 };
238
239 /// Table of known job types and their sizes.
242 #endif
243
244 /// Special synchronization job. Pushed with #"ThreadPool::Sync;2" and
245 /// #"DedicatedWorker::DeleteJobDeferred;2"
246 /// With the latter, the field #".JobToDelete" will be given, otherwise this is nulled.
247 struct JobSyncer : Job
248 {
249 /// Optionally a job to be deleted.
251
252 /// Constructor.
253 /// @param job The job that is scheduled to be deleted.
255 : Job(typeid(JobSyncer))
256 , JobToDelete(job) {}
257
258 /// Overrides the parent function as necessary.
259 /// @return The sizeof this derived type.
260 virtual size_t SizeOf() override { return sizeof(JobSyncer); }
261 };
262
263 //================================================================================================
264 // The queue
265 //================================================================================================
266 /// Container element of the queue.
268 {
269 Job* job; ///< The job.
270 bool keep; ///< If true, the job is not deleted by the processing worker,
271 ///< but has to be deleted by the caller.
272 };
273
274 /// The queue of jobs.
276
277
278 /// The number of Jobs that have been scheduled during the lifetime of this instance.
280
281 /// The number of jobs currently in the queue.
282 int ctdOpenJobs {0};
283
284 /// Mandatory method needed and invoked by templated base type #"TCondition".
285 /// @return \c true if the field #queue is not empty and either no sync-job is next or
286 /// all are idle.
288 return queue.IsNotEmpty()
289 && ( queue.back().job->ID != typeid(JobSyncer)
290 || ctdIdle == ctdWorkers );
291 }
292
293 /// Pushes the given \p{cmd} into the priority queue that this class implements.
294 /// @param entry The Job and the deletion flag.
296 // insert before found
297 queue.emplace_front( entry );
298 ++ctdOpenJobs;
300
301 ALIB_MESSAGE( "TMOD/QUEUE", "{} Job({}) pushed",
302 this, &entry.job->ID )
303
305 }
306
307 /// Set if the last thread is terminated and #ctdWorkers goes to \c 0.
308 /// This thread is joined by #Shutdown or when a new thread is added.
310
311 /// Moves the job of highest priority out of the queue.
312 /// Blocks the thread until a job is available.
313 /// @param worker The instance that called this method.
314 /// @return The job with the highest priority.
316
317 /// Internal method that adds a thread. Must only be called when acquired.
319 void addThread();
320
321 /// Implementation of #Schedule and #ScheduleVoid.
322 /// @tparam TJob The job type to create and schedule.
323 /// @tparam TArgs Types of the variadic arguments \p{args} that construct \p{TJob}.
324 /// @param keepJob Denotes whether the job should be deleted after execution or not.
325 /// @param args Variadic arguments forwarded to the constructor of \p{TJob}.
326 /// @return The scheduled job.
327 template<typename TJob, typename... TArgs>
328 [[nodiscard]]
329 TJob* schedule( bool keepJob, TArgs&&... args ) {
331 // first check if this pool is active (has threads)
332 if (ctdWorkers == 0) {
333 ALIB_ASSERT_ERROR( Strategy.WorkersMax > 0
335 || Strategy.WorkersMax > 0 ), "TMOD/STRGY",
336 "No threads to schedule job. Strategy values:\n"
337 " WorkersMax: {}\n"
338 " Strategy.Mode: ",
339 Strategy.WorkersMax ,
340 Strategy.Mode == ResizeStrategy::Modes::Auto ? "Auto" : "Fixed" )
341
342 addThread();
343 }
344 TJob* job= pool().New<TJob>( std::forward<TArgs>(args)... );
345 ALIB_ASSERT_ERROR( job->SizeOf()==sizeof(TJob), "TMOD",
346 "{} error in schedule: Job size mismatch. Expected {} "
347 "while virtual method SizeOf returns {}.\n"
348 "Override this method for job-type <{}>", this, sizeof(TJob), job->SizeOf(), &typeid(*job) )
349
350 ALIB_ASSERT_ERROR( Strategy.WorkersMax > 0, "TMOD",
351 "{} error: Job pushed while this pool is shut down already. "
352 "(Strategy.WorkersMax == 0) ", this )
353
354 #if ALIB_DEBUG
355 auto pair= DbgKnownJobs.EmplaceIfNotExistent( DbgKnownJobsEntry{ &typeid(TJob),
356 sizeof(TJob), 0 } );
357 ++pair.first.Value().Usage;
358 #endif
359
360 pushAndRelease( {job, keepJob} );
361 return job;
362 }
363
364 public:
365 /// The parameters used for scaling the amount of worker threads.
366 /// The values herein can be changed from outside with direct access.
368
369 /// The wait-time slice used by method #WaitForAllIdle.
370 Ticks::Duration IdleWaitTime = Ticks::Duration::FromAbsoluteMicroseconds(50);
371
372 /// Constructor.
373 /// Initializes the thread pool with default settings for field #Strategy.
375
376 #if ALIB_DEBUG_CRITICAL_SECTIONS
377 /// Destructor. Cleans up and shuts down the thread pool.
379
380 /// @return \c true if the lock is acquired (in non-shared mode), \c false otherwise.
381 ALIB_DLL bool DCSIsAcquired() const override;
382
383 /// @return \c true if the lock is shared-acquired (by at least any thread).
384 /// Otherwise, returns \c false.
385 ALIB_DLL bool DCSIsSharedAcquired() const override;
386 #else
387 virtual
389 #endif
390
393
394 /// Returns the mono allocator used by the thread pool.
395 /// The pool has to be acquired before using it.
396 /// @return The mono allocator.
398
399 /// Returns the pool allocator used by the thread pool.
400 /// The pool has to be acquired before using it.
401 /// @return The pool allocator.
403
404 /// Creates a worker using the #pool allocator.
405 /// Derived types may override this method and create a derived #"PoolWorker"-type.
406 /// @return A pool worker.
408
409 /// Destructs the given pool worker.
410 /// Derived types may add further logic here.
411 /// @param poolWorker The pool worker to destruct and delete.
412 virtual void DisposeWorker( PoolWorker* poolWorker );
413
414 /// Just an alias to
415 /// \https{Empty Base Optimization,en.cppreference.com/w/cpp/thread/thread/hardware_concurrency}.
416 ///
417 /// While the specification says
418 /// <em>"If the value is not well-defined or not computable, returns \c 0"</em>,
419 /// this method returns \c 1 in this case.
420 ///
421 /// Used as the default value for constructor parameter \p{pWorkersMax}.
422 /// @return Returns the maximum number of threads that can be expected to run concurrently.
423 static int HardwareConcurrency() noexcept
424 { return int(std::thread::hardware_concurrency()); }
425
426 /// Returns the current number of worker threads.
427 /// @return The number of jobs to process, including any currently processed one.
428 int CountedWorkers() const { return ctdWorkers; }
429
430 /// Returns the current number of idle workers.
431 /// @return The number of workers waiting on jobs to process.
432 int CountedIdleWorkers() const { return ctdIdle; }
433
434 /// Checks if all workers are idle.
435 /// @return \c true if the number of idle workers equals the number of workers,
436 /// \c false otherwise.
437 bool IsIdle() const { return ctdIdle == ctdWorkers; }
438
439 /// Pushes a job of the custom type \p{TJob} into the priority queue.<br>
440 /// The job is returned to the caller to be able to await results.
441 /// It is the responsibility of the caller to pass the job to either method
442 /// #DeleteJob or #DeleteJobDeferred for disposal.
443 /// Note that the latter causes a #Sync on this pool, while with use of the former,
444 /// the fulfilment of the returned job object has to be awaited first.
445 /// @tparam TJob The job type to create and schedule.
446 /// @tparam TArgs Types of the variadic arguments \p{args} that construct \p{TJob}.
447 /// @param args Variadic arguments forwarded to the constructor of \p{TJob}.
448 /// @return A reference to the job object for the caller to await results.
449 template<typename TJob, typename... TArgs>
450 [[nodiscard]]
451 TJob& Schedule( TArgs&&... args )
452 { return *schedule<TJob, TArgs...>( true, std::forward<TArgs>(args)... ); }
453
454 /// Pushes a job of the custom type \p{TJob} into the priority queue.
455 /// In contrast to the sibling method #Schedule, the job is not returned by this method.
456 /// Instead, it is scheduled for automatic disposal after execution.
457 /// @tparam TJob The job type to create and schedule.
458 /// @tparam TArgs Types of the variadic arguments \p{args} that construct \p{TJob}.
459 /// @param args Variadic arguments forwarded to the constructor of \p{TJob}.
460 template<typename TJob, typename... TArgs>
461 void ScheduleVoid( TArgs&&... args )
462 { (void) schedule<TJob, TArgs...>( false, std::forward<TArgs>(args)... ); }
463
464 /// Deletes a job object previously scheduled with #Schedule.
465 ///
466 /// \attention
467 /// The caller must not delete received job instances before they are processed.
468 ///
469 /// \attention
470 /// In case a caller does not want to wait longer, the method #DeleteJobDeferred is to be used,
471 /// which causes a #Sync on this pool.
472 /// Therefore, it is preferable to either wait on the job and use this method for deletion,
473 /// or to use the method #ScheduleVoid instead of #Schedule to not even get involved
474 /// with job-deletion.
475 ///
476 /// @param job The job returned from method #Schedule.
477 void DeleteJob(Job& job) {
479 auto size= job.SizeOf();
480 job.~Job();
481 pool.free(&job, size);
482 }
483
484 /// Same as #DeleteJob but schedules the deletion to be performed.
485 /// This method is useful when a job instance was received with the method #Schedule, but the
486 /// caller does not want to continue waiting for the execution of the job.<br>
487 /// If jobs indicate that they have been processed, then the method #DeleteJob is to be used.
488 ///
489 /// \attention Calling this method schedules a #Sync.
490 /// Therefore, the use of this method should be avoided.
491 ///
492 /// @see Methods #ScheduleVoid, #DeleteJob and #Sync.
493 /// @param job The job object to delete.
494 void DeleteJobDeferred(Job& job) { (void) schedule<JobSyncer>(false, &job); }
495
496 /// This method ensures all worker threads in the thread pool complete their currently running
497 /// jobs and also process all jobs that have been scheduled before a call to this method.
498 /// This forces synchronization such that no new jobs are processed until the
499 /// synchronization request is fulfilled.<br>
500 /// It is particularly useful for scenarios requiring a consistent state or ensuring all pending
501 /// asynchronous jobs are complete before proceeding.
502 ///
503 /// Consequently, a call to this method may inherently involve blocking the execution in the
504 /// pool until all prior tasks are finalized. While it is designed to work efficiently with the
505 /// thread pool mechanism, unnecessary or frequent calls to this method impose a performance
506 /// disadvantage.
507 ///
508 /// Invoking \b %Sync() schedules #"JobSyncer;a special synchronization job" in the queue of
509 /// this \b %ThreadPool.
510 /// Thus, the method is non-blocking and instantly returns.
511 ///
512 /// \par Necessity for Synchronization Explained with a Sample:
513 /// The requirement for synchronization is best illustrated with a practical scenario.
514 /// Consider a case where the main thread is responsible for scanning the filesystem.
515 /// For each file that meets certain criteria, a job is scheduled in the \b ThreadPool
516 /// to read the content of that file.
517 /// At this stage, the main thread is focused solely on scheduling file-reading jobs and
518 /// isn't directly processing the files.
519 ///
520 /// \par
521 /// Now, before the application proceeds to schedule further jobs, such as processing,
522 /// analyzing, or aggregating the file data, it is crucial to ensure that all file-reading
523 /// jobs have completed.
524 /// Without a synchronization mechanism, there is a risk that some worker threads are still
525 /// reading files while other threads - already assigned to the dependent processing tasks —
526 /// begin before the file data is available.
527 ///
528 /// \par
529 /// A call to \b %Sync() resolves this issue by ensuring that all file-reading jobs are
530 /// completed before any subsequent jobs that rely on their output are scheduled or processed.
531 /// This guarantees consistency, prevents race conditions, and ensures that no dependent
532 /// thread gets an incomplete or inconsistent dataset to work with.
533 /// In summary, synchronization acts as a safeguard in parallelized workflows where the
534 /// logical order of operations must be maintained across multiple threads, particularly
535 /// when tasks are interdependent.
536 ///
537 /// @see Method #DeleteJobDeferred, which likewise causes a synchronization.
538 void Sync() { (void) schedule<JobSyncer>(false, nullptr); }
539
540 #if DOXYGEN
541 /// Waits until all threads are idle.
542 /// @param timeout The maximum time to wait.
543 /// @param dbgWarnAfter The time after which a warning message will be printed to the
544 /// debug log if the timeout was reached.<br>
545 /// This parameter is only available in debug-compilations and thus
546 /// should be passed using macro #"ALIB_DBG".
547 /// @return \c true if all threads are idle, \c false otherwise.
549 bool WaitForAllIdle( Ticks::Duration timeout,
550 Ticks::Duration dbgWarnAfter );
551 #else
552 ALIB_DLL bool WaitForAllIdle( Ticks::Duration timeout
553 ALIB_DBG(, Ticks::Duration dbgWarnAfter) );
554 bool WaitForAllIdle( Ticks::Duration::TDuration timeout
555 ALIB_DBG(, Ticks::Duration::TDuration dbgWarnAfter) )
556 { return WaitForAllIdle( Ticks::Duration(timeout) ALIB_DBG(,Ticks::Duration(dbgWarnAfter))); }
557
558 #endif
559
560 /// Removes all threads.
561 /// While this method waits that all jobs are finalized just as the method #WaitForAllIdle does,
562 /// it is recommended to #WaitForAllIdle explicitly, before this method is called.
563 /// This allows a more graceful shutdown with the possibility to take action on timeouts.
564 ///
565 /// If after the call to \b WaitForAllIdle no jobs were scheduled, this method is \b not #
566 /// supposed to block.
568 void Shutdown();
569
570 /// Returns the current number of jobs in the queue.
571 /// \note To get the overall number of unprocessed jobs, the difference between
572 /// #CountedWorkers and #CountedIdleWorkers has to be added.
573 /// However, under racing conditions, this difference might evaluated wrongly.
574 /// Therefore, if crucial, this pool has to be acquired before determining this.
575 /// @return The number of jobs to process, not including any currently processed one.
576 int CountedOpenJobs() const { return ctdOpenJobs; }
577
578 /// Returns the number of Jobs that have been scheduled during the lifetime of this instance.
579 /// This is a statistics method.
580 /// @return The number of jobs to process, including any currently processed one.
582
583 #if ALIB_DEBUG && ALIB_STRINGS
584 /// Writes the list of known jobs and their object sizes to the given target.
585 /// \par Availability
586 /// This function is available only with debug-compilations and if the module
587 /// \alib_strings is included in the\alibbuild.
588 /// @see Field DbgDumpKnownJobs.
589 ///
590 /// @param target The string to write to.
591 /// @param linePrefix A prefix string to each line. Defaults to two spaces.
592 /// @return The number of known jobs.
594 int DbgDumpKnownJobs(NAString& target, const NString& linePrefix= " " );
595 #endif
596
597}; // class ThreadPool
598
599} // namespace alib[::threadmodel]
600
601/// Type alias in namespace \b alib.
603
604/// Type alias in namespace \b alib.
606
607} // namespace [alib]
608
609//##################################################################################################
610// struct AppendableTraits<ThreadPool>
611//##################################################################################################
612
613#if ALIB_STRINGS
614// Faking all template specializations of namespace strings for doxygen into namespace
615// strings::APPENDABLES to keep the documentation of namespace string clean!
616namespace alib::strings {
617#if DOXYGEN
618namespace APPENDABLES {
619#endif
620
621/// Specialization of functor #"AppendableTraits" for type #"ThreadPool".
623{
624 /// Writes some information about the given \b ThreadPool.
625 /// @param target The \b NAString that \b Append was invoked on.
626 /// @param tpool The thread pool instance.
627 void operator()( AString& target, const alib::threadmodel::ThreadPool& tpool );
628};
629
630#if DOXYGEN
631} // namespace alib::strings[APPENDABLES]
632#endif
633} // namespace [alib::strings]
634#endif
#define ALIB_MESSAGE(domain,...)
Definition alib.inl:1142
#define ALIB_DLL
Definition alib.inl:573
#define ALIB_EXPORT
Definition alib.inl:562
#define ALIB_LOCK
Definition alib.inl:1410
#define ALIB_DBG(...)
Definition alib.inl:931
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1144
#define ALIB_CALLER_PRUNED
Definition alib.inl:1102
bool DCSIsSharedAcquired() const override
int ctdWorkers
The counted number of currently of workers.
Ticks::Duration IdleWaitTime
The wait-time slice used by method WaitForAllIdle.
int ctdIdle
The counted number of currently idle workers.
PoolAllocator pool
Pool allocator. Used for job objects.
static int HardwareConcurrency() noexcept
void pushAndRelease(QueueEntry &&entry)
uinteger StatsCountedScheduledJobs() const
void Acquire(ALIB_DBG_TAKE_CI)
MonoAllocator & GetAllocator()
int DbgDumpKnownJobs(NAString &target, const NString &linePrefix=" ")
virtual void DisposeWorker(PoolWorker *poolWorker)
TJob & Schedule(TArgs &&... args)
HashTable< MonoAllocator, DbgKnownJobsVD > DbgKnownJobs
Table of known job types and their sizes.
int ctdOpenJobs
The number of jobs currently in the queue.
ListPA< QueueEntry, Recycling::None > queue
The queue of jobs.
QueueEntry pop(PoolWorker *worker)
bool WaitForAllIdle(Ticks::Duration timeout, Ticks::Duration dbgWarnAfter)
TJob * schedule(bool keepJob, TArgs &&... args)
void addThread()
Internal method that adds a thread. Must only be called when acquired.
PoolAllocator & GetPoolAllocator()
~ThreadPool() override
Destructor. Cleans up and shuts down the thread pool.
HashSet< MonoAllocator, PoolWorker * > workers
The list of worker threads.
bool DCSIsAcquired() const override
virtual PoolWorker * CreateWorker()
uinteger ctdStatJobsScheduled
The number of Jobs that have been scheduled during the lifetime of this instance.
MonoAllocator ma
Mono allocator. Used for jobs and by PoolWorkers.
Ticks timeOfLastSizeChange
The point in time of the last change of thread size.
void ScheduleVoid(TArgs &&... args)
Thread(const character *pName=A_CHAR(""))
Definition thread.inl:181
virtual void SetName(const character *newName)
Definition thread.inl:247
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
strings::TString< nchar > NString
Type alias in namespace alib.
Definition string.inl:2181
containers::HashSet< TAllocator, T, THash, TEqual, THashCaching, TRecycling > HashSet
Type alias in namespace alib. See type definition #"alib::containers::HashSet".
threads::Thread Thread
Type alias in namespace alib.
Definition thread.inl:387
containers::HashTable< TAllocator, TValueDescriptor, THash, TEqual, THashCaching, TRecycling > HashTable
Type alias in namespace alib. See type definition #"alib::containers::HashSet".
LocalString< 64 > String64
Type alias name for #"TLocalString;TLocalString<character,64>".
strings::TAString< nchar, lang::HeapAllocator > NAString
Type alias in namespace alib.
monomem::TPoolAllocator< MonoAllocator > PoolAllocator
containers::List< T, PoolAllocator, TRecycling > ListPA
Type alias in namespace alib.
Definition list.inl:701
time::Ticks Ticks
Type alias in namespace alib.
Definition ticks.inl:79
threadmodel::ThreadPool ThreadPool
Type alias in namespace alib.
strings::TAString< character, lang::HeapAllocator > AString
Type alias in namespace alib.
characters::character character
Type alias in namespace alib.
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.inl:152
threadmodel::PoolWorker PoolWorker
Type alias in namespace alib.
virtual size_t SizeOf()
Definition jobs.inl:95
Job(const std::type_info &id)
Definition jobs.inl:63
virtual ~Job()=default
Protected destructor.
virtual void PrepareJob(Job *job)
ThreadPool & threadPool
The pool that this instance belongs to.
String64 nameBuffer
Buffer to store the thread name given with construction.
PoolWorker(ThreadPool &pThreadPool, const character *threadName)
Entry in the field #"DbgKnownJobs".
size_t Usage
Counter of scheduled jobs of this type.
size_t JobSize
The size of the job object.
const std::type_info * TID
The job type.
Serves as template parameter TValueDescriptor of field #"DbgKnownJobs".
const std::type_info * Key(DbgKnownJobsEntry &entry) const
Job * JobToDelete
Optionally a job to be deleted.
Container element of the queue.
int WorkersMin
The minimum number of threads to keep alive.
int GetSize(int currentWorkers, int idleWorkers, int load, Ticks &lastChangeTime)
TCondition(const character *dbgName)
void Release(ALIB_DBG_TAKE_CI)
void Acquire(ALIB_DBG_TAKE_CI)
void ReleaseAndNotify(ALIB_DBG_TAKE_CI)