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