BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlmt_threadpool.h
Go to the documentation of this file.
1/// @file bdlmt_threadpool.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlmt_threadpool.h -*-C++-*-
8#ifndef INCLUDED_BDLMT_THREADPOOL
9#define INCLUDED_BDLMT_THREADPOOL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlmt_threadpool bdlmt_threadpool
15/// @brief Provide portable implementation for a dynamic pool of threads.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlmt
19/// @{
20/// @addtogroup bdlmt_threadpool
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlmt_threadpool-purpose"> Purpose</a>
25/// * <a href="#bdlmt_threadpool-classes"> Classes </a>
26/// * <a href="#bdlmt_threadpool-metrics"> Metrics </a>
27/// * <a href="#bdlmt_threadpool-description"> Description </a>
28/// * <a href="#bdlmt_threadpool-thread-safety"> Thread Safety </a>
29/// * <a href="#bdlmt_threadpool-synchronous-signals-on-unix"> Synchronous Signals on Unix </a>
30/// * <a href="#bdlmt_threadpool-usage"> Usage </a>
31/// * <a href="#bdlmt_threadpool-setting-threadpool-attributes"> Setting ThreadPool Attributes </a>
32/// * <a href="#bdlmt_threadpool-the-void-functionvoid-pointer-interface"> The "void functionvoid pointer" Interface </a>
33/// * <a href="#bdlmt_threadpool-the-functor-interface"> The Functor Interface </a>
34///
35/// # Purpose {#bdlmt_threadpool-purpose}
36/// Provide portable implementation for a dynamic pool of threads.
37///
38/// # Classes {#bdlmt_threadpool-classes}
39///
40/// - bdlmt::ThreadPool: portable dynamic thread pool
41///
42/// # Metrics {#bdlmt_threadpool-metrics}
43///
44///
45/// * `bde.backlog`
46/// > number of pending jobs minus number of "idle" threads in the thread pool
47/// > (may be negative)
48///
49/// Associated Metric Attributes:
50/// * object type name: "bdlmt.threadpool"
51/// * object type abbreviation: "tp"
52///
53/// @see
54///
55/// # Description {#bdlmt_threadpool-description}
56/// This component defines a portable and efficient implementation
57/// of a thread pool that can be used to distribute various user-defined
58/// functions ("jobs") to separate threads and execute the jobs concurrently.
59/// The thread pool manages a dynamic set of processing threads, adding or
60/// removing threads to manage load, based upon user-defined parameters.
61///
62/// The pool uses a queue mechanism to distribute work among the threads. Jobs
63/// are queued for execution as they arrive, and each queued job is processed by
64/// the next available thread. If no threads are available, new threads are
65/// created dynamically (up to the application defined maximum number). If the
66/// maximum number of concurrent threads has been reached, new jobs will remain
67/// enqueued until a thread becomes available. If the threads become idle for
68/// longer than a user-defined maximum idle time, they are automatically
69/// destroyed, releasing unused resources. A client-defined minimum number of
70/// threads is always maintained even when there is no work to be done.
71///
72/// The thread pool provides two interfaces for specifying jobs: the commonly
73/// used "void function/void pointer" interface and the more versatile functor
74/// based interface. The void function/void pointer interface allows callers to
75/// use a C-style function to be executed as a job. The application need only
76/// specify the address of the function, and a single void pointer argument, to
77/// be passed to the function. The specified function will be invoked with the
78/// specified argument by the processing thread. The functor based interface
79/// allows for flexible job execution such as the invocation of member functions
80/// or the passing of multiple user-defined arguments. See the `bdef` package
81/// documentation for more on functors and their usage.
82///
83/// An application can tune the thread pool by adjusting the minimum and maximum
84/// number of threads in the pool, and the maximum amount of time that
85/// dynamically created threads can idle before being destroyed. To avoid
86/// unnecessary and inefficient thread creation/destruction, an application
87/// should select a value for the minimum number of threads that reflects the
88/// expected average load. A higher value for the maximum number of threads can
89/// be used to handle periodic bursts. An application can also specify the
90/// attributes of the threads in the pool (e.g., thread priority or stack size),
91/// by providing a `bslmt::ThreadAttributes` object with the desired values set.
92/// See @ref bslmt_threadutil package documentation for a description of
93/// `bslmt::ThreadAttributes`.
94///
95/// Thread pools are ideal for developing multi-threaded server applications. A
96/// server need only package client requests to execute as jobs, and
97/// `bdlmt::ThreadPool` will handle the queue management, thread management, and
98/// request dispatching. Thread pools are also well suited for parallelizing
99/// certain types of application logic. Without any complex or redundant thread
100/// management code, an application can easily create a thread pool, enqueue a
101/// series of jobs to be executed, and wait until all the jobs have executed.
102///
103/// ## Thread Safety {#bdlmt_threadpool-thread-safety}
104///
105///
106/// The `bdlmt::ThreadPool` class is both **fully thread-safe** (i.e., all
107/// non-creator methods can correctly execute concurrently), and is
108/// **thread-enabled** (i.e., the class does not function correctly in a
109/// non-multi-threading environment). See @ref bsldoc_glossary for complete
110/// definitions of **fully thread-safe** and **thread-enabled**.
111///
112/// ## Synchronous Signals on Unix {#bdlmt_threadpool-synchronous-signals-on-unix}
113///
114///
115/// A thread pool ensures that, on unix platforms, all the threads in the pool
116/// block all asynchronous signals. Specifically all the signals, except the
117/// following synchronous signals are blocked.
118///
119/// SIGBUS
120/// SIGFPE
121/// SIGILL
122/// SIGSEGV
123/// SIGSYS
124/// SIGABRT
125/// SIGTRAP
126/// SIGIOT
127///
128/// ## Usage {#bdlmt_threadpool-usage}
129///
130///
131/// This example demonstrates the use of a `bdlmt::ThreadPool` to parallelize a
132/// segment of program logic. The example implements a multi-threaded file
133/// search utility. The utility searches multiple files for a string, similar
134/// to the Unix command `fgrep`; the use of a `bdlmt::ThreadPool` allows the
135/// utility to search multiple files concurrently.
136///
137/// The example program will take as input a string and a list of files to
138/// search. The program creates a `bdlmt::ThreadPool`, and then enqueues a
139/// single "job" for each file to be searched. Each thread in the pool will
140/// take a job from the queue, open the file, and search for the string. If a
141/// match is found, the job adds the filename to an array of matching filenames.
142/// Because this array of filenames is shared across multiple jobs and across
143/// multiple threads, access to the array is controlled via a `bslmt::Mutex`.
144///
145/// ### Setting ThreadPool Attributes {#bdlmt_threadpool-setting-threadpool-attributes}
146///
147///
148/// To get started, we declare thread attributes, to be used in constructing the
149/// thread pool. In this example, our choices for minimum search threads and
150/// maximum idle time are arbitrary; we don't expect the thread pool to become
151/// idle, so the thread pool should not begin to delete unused threads before
152/// the program terminates.
153///
154/// However, a maximum number of 50 threads is meaningful, and may affect
155/// overall performance. The maximum should cover the expected peak, in this
156/// case, the maximum number of files to search. However, if the maximum is too
157/// large for a given platform, it may cause a bottleneck as the operating
158/// system spends significant resources switching context among multiple
159/// threads. Also we use a very short idle time since new jobs will arrive only
160/// at startup.
161/// @code
162/// const int MIN_SEARCH_THREADS = 10;
163/// const int MAX_SEARCH_THREADS = 50;
164/// const bsls::TimeInterval MAX_SEARCH_THREAD_IDLE(0, 100000000);
165/// @endcode
166/// Below is the structure that will be used to pass arguments to the file
167/// search function. Since each job will be searching a separate file, a
168/// distinct instance of the structure will be used for each job.
169/// @code
170/// struct my_FastSearchJobInfo {
171/// const bsl::string *d_word; // word to search for
172/// const bsl::string *d_path; // path of the file to search
173/// bslmt::Mutex *d_mutex; // mutex to control access to the
174/// // result file list
175/// bsl::vector<bsl::string> *d_outList; // list of matching files
176/// };
177/// @endcode
178///
179/// ### The "void functionvoid pointer" Interface {#bdlmt_threadpool-the-void-functionvoid-pointer-interface}
180///
181///
182/// `myFastSearchJob` is the search function to be executed as a job by threads
183/// in the thread pool, matching the "void function/void pointer" interface.
184/// The single `void *` argument is received and cast to point to a 'struct
185/// my_FastSearchJobInfo', which then points to the search string and a single
186/// file to be searched. Note that different `my_FastSearchJobInfo` structures
187/// for the same search request will differ only in the attribute `d_path`,
188/// which points to a specific filename among the set of files to be searched;
189/// other fields will be identical across all structures for a given Fast
190/// Search.
191///
192/// See the following section for an illustration of the functor interface.
193/// @code
194/// static void myFastSearchJob(void *arg)
195/// {
196/// my_FastSearchJobInfo *job = (my_FastSearchJobInfo*)arg;
197/// FILE *file;
198///
199/// file = fopen(job->d_path->c_str(), "r");
200///
201/// if (file) {
202/// char buffer[1024];
203/// size_t nread;
204/// size_t wordLen = job->d_word->length();
205/// const char *word = job->d_word->c_str();
206///
207/// nread = fread(buffer, 1, sizeof(buffer) - 1, file);
208/// while(nread >= wordLen) {
209/// buffer[nread] = 0;
210/// if (strstr(buffer, word)) {
211/// @endcode
212/// If we find a match, we add the file to the result list and return. Since
213/// the result list is shared among multiple processing threads, we use a mutex
214/// lock to regulate access to the list. We use a `bslmt::LockGuard` to manage
215/// access to the mutex lock. This template object acquires a mutex lock on
216/// `job->d_mutex` at construction, releases that lock on destruction. Thus,
217/// the mutex will be locked within the scope of the `if` block, and released
218/// when the program exits that scope.
219///
220/// See @ref bslmt_threadutil for information about the `bslmt::Mutex` class, and
221/// component @ref bslmt_lockguard for information about the `bslmt::LockGuard`
222/// template class.
223/// @code
224/// bslmt::LockGuard<bslmt::Mutex> lock(job->d_mutex);
225/// job->d_outList->push_back(*job->d_path);
226/// break; // bslmt::LockGuard destructor unlocks mutex.
227/// }
228/// memcpy(buffer, &buffer[nread - wordLen - 1], wordLen - 1);
229/// nread = fread(buffer + wordLen - 1, 1, sizeof(buffer) - wordLen,
230/// file);
231/// }
232/// fclose(file);
233/// }
234/// }
235/// @endcode
236/// Routine `myFastSearch` is the main driving routine, taking three arguments:
237/// a single string to search for (`word`), a list of files to search, and an
238/// output list of files. When the function completes, the file list will
239/// contain the names of files where a match was found.
240/// @code
241/// void myFastSearch(const bsl::string& word,
242/// const bsl::vector<bsl::string>& fileList,
243/// bsl::vector<bsl::string>& outFileList)
244/// {
245/// bslmt::Mutex mutex;
246/// bslmt::ThreadAttributes defaultAttributes;
247/// @endcode
248/// We initialize the thread pool using default thread attributes. We then
249/// start the pool so that the threads can begin while we prepare the jobs.
250/// @code
251/// bdlmt::ThreadPool pool(defaultAttributes,
252/// MIN_SEARCH_THREADS,
253/// MAX_SEARCH_THREADS,
254/// MAX_SEARCH_THREAD_IDLE);
255///
256/// if (0 != pool.start()) {
257/// bsl::cerr << "Failed to start minimum number of threads.\n";
258/// exit(1);
259/// }
260/// @endcode
261/// For each file to be searched, we create the job info structure that will be
262/// passed to the search function and add the job to the pool.
263///
264/// As noted above, all jobs will share a single mutex to guard the output file
265/// list. Function `myFastSearchJob` uses a `bslmt::LockGuard` on this mutex to
266/// serialize access to the list.
267/// @code
268/// int count = fileList.size();
269/// my_FastSearchJobInfo *jobInfoArray = new my_FastSearchJobInfo[count];
270///
271/// for (int i = 0; i < count; ++i) {
272/// my_FastSearchJobInfo &job = jobInfoArray[i];
273/// job.d_word = &word;
274/// job.d_path = &fileList[i];
275/// job.d_mutex = &mutex;
276/// job.d_outList = &outFileList;
277/// pool.enqueueJob(myFastSearchJob, &job);
278/// }
279/// @endcode
280/// Now we simply wait for all the jobs in the queue to complete. Any matched
281/// files should have been added to the output file list.
282/// @code
283/// pool.drain();
284/// delete[] jobInfoArray;
285/// }
286/// @endcode
287///
288/// ### The Functor Interface {#bdlmt_threadpool-the-functor-interface}
289///
290///
291/// The "void function/void pointer" convention is idiomatic for C programs.
292/// The `void` pointer argument provides a generic way of passing in user data,
293/// without regard to the data type. Clients who prefer better or more explicit
294/// type safety may wish to use the Functor Interface instead. This interface
295/// uses the `bsl::function` component to provide type-safe wrappers that can
296/// match argument number and type for a C++ free function or member function.
297///
298/// To illustrate the Functor Interface, we will make two small changes to the
299/// usage example above. First, we change the signature of the function that
300/// executes a single job, so that it uses a `my_FastSearchJobInfo` pointer
301/// rather than a `void` pointer. With this change, we can remove the first
302/// executable statement, which casts the `void *` pointer to
303/// `my_FastSearchJobInfo *`.
304/// @code
305/// static void my_FastFunctorSearchJob(my_FastSearchJobInfo *job)
306/// {
307/// FILE *file;
308///
309/// file = fopen(job->d_path->c_str(), "r");
310///
311/// // The rest of the function is unchanged.
312/// if (file) {
313/// char buffer[1024];
314/// size_t nread;
315/// size_t wordLen = job->d_word->length();
316/// const char *word = job->d_word->c_str();
317///
318/// nread = fread(buffer, 1, sizeof(buffer) - 1, file);
319/// while(nread >= wordLen) {
320/// buffer[nread] = 0;
321/// if (strstr(buffer, word)) {
322/// bslmt::LockGuard<bslmt::Mutex> lock(job->d_mutex);
323/// job->d_outList->push_back(*job->d_path);
324/// break; // bslmt::LockGuard destructor unlocks mutex.
325/// }
326/// }
327/// bsl::memcpy(buffer, &buffer[nread - wordLen - 1], wordLen - 1);
328/// nread = fread(buffer + wordLen - 1, 1, sizeof(buffer) - wordLen,
329/// file);
330/// }
331/// fclose(file);
332/// }
333/// @endcode
334/// Next, we make a change to the loop that enqueues the jobs in `myFastSearch`.
335/// The function starts exactly as in the previous example:
336/// @code
337/// static void myFastFunctorSearch(const string& word,
338/// const vector<string>& fileList,
339/// vector<string>& outFileList)
340/// {
341/// bslmt::Mutex mutex;
342/// bslmt::ThreadAttributes defaultAttributes;
343/// bdlmt::ThreadPool pool(defaultAttributes,
344/// MIN_SEARCH_THREADS,
345/// MAX_SEARCH_THREADS,
346/// MAX_SEARCH_THREAD_IDLE);
347///
348/// if (0 != pool.start()) {
349/// bsl::cerr << "Failed to start minimum number of threads. "
350/// << "Thread quota exceeded?\n";
351/// assert(false);
352/// return; // things are SNAFU
353/// }
354///
355/// int count = fileList.size();
356/// my_FastSearchJobInfo *jobInfoArray = new my_FastSearchJobInfo[count];
357/// @endcode
358/// We create a functor - a C++ object that acts as a function. The thread pool
359/// will "execute" this functor (by calling its `operator()` member function) on
360/// a thread when one becomes available.
361/// @code
362/// for (int i = 0; i < count; ++i) {
363/// my_FastSearchJobInfo &job = jobInfoArray[i];
364/// job.d_word = &word;
365/// job.d_path = &fileList[i];
366/// job.d_mutex = &mutex;
367/// job.d_outList = &outFileList;
368///
369/// bsl::function<void()> jobHandle =
370/// bdlf::BindUtil::bind(&my_FastFunctorSearchJob, &job);
371/// pool.enqueueJob(jobHandle);
372/// }
373/// @endcode
374/// Note that the functor is created locally and handed to the thread pool. The
375/// thread pool copies the functor onto its internal queue, and takes
376/// responsibility for the copied functor until execution is complete.
377///
378/// The function is completed exactly as it was in the previous example.
379/// @code
380/// pool.drain();
381/// delete[] jobInfoArray;
382/// }
383/// @endcode
384/// @}
385/** @} */
386/** @} */
387
388/** @addtogroup bdl
389 * @{
390 */
391/** @addtogroup bdlmt
392 * @{
393 */
394/** @addtogroup bdlmt_threadpool
395 * @{
396 */
397
398#include <bdlf_bind.h>
399
400#include <bdlscm_version.h>
401
402#include <bdlm_metricsregistry.h>
403
404#include <bslma_allocator.h>
406
408#include <bslmf_movableref.h>
410
412#include <bslmt_condition.h>
413#include <bslmt_mutex.h>
414#include <bslmt_threadutil.h>
415
416#include <bsls_atomic.h>
418#include <bsls_platform.h>
419#include <bsls_timeinterval.h>
420
421#include <bsl_deque.h>
422#if defined(BSLS_PLATFORM_OS_UNIX)
423 #include <bsl_csignal.h> // sigfillset
424#endif
425#include <bsl_functional.h>
426#include <bsl_string.h>
427
428#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
429#include <bslalg_typetraits.h>
430#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
431
432
433
434#ifndef BDE_OMIT_INTERNAL_DEPRECATED
435
436/// This type declares the prototype for functions that are suitable to
437/// be specified `bdlmt::FixedThreadPool::enqueueJob`.
438extern "C" typedef void (*bcep_ThreadPoolJobFunc)(void *);
439
440#endif // BDE_OMIT_INTERNAL_DEPRECATED
441
442namespace bdlmt {
443
444struct ThreadPoolWaitNode;
445
446/// Entry point for processing threads.
447extern "C" void *ThreadPoolEntry(void *);
448
449/// This type declares the prototype for functions that are suitable to be
450/// specified `bdlmt::FixedThreadPool::enqueueJob`.
451extern "C" typedef void (*ThreadPoolJobFunc)(void *);
452
453 // ================
454 // class ThreadPool
455 // ================
456
457/// This class implements a thread pool used for concurrently executing
458/// multiple user-defined functions ("jobs").
459///
460/// See @ref bdlmt_threadpool
462
463 public:
464 // TYPES
465 typedef bsl::function<void()> Job;
466
467 private:
468 // PRIVATE DATA
469 bsl::deque<Job> d_queue; // queue of pending jobs
470
471 mutable bslmt::Mutex d_mutex; // mutex used to control access to
472 // this thread pool
473
474 bslmt::Condition d_drainCond; // condition variable used to signal
475 // that the queue is fully drained
476 // and that all active jobs have
477 // completed
478
480 d_threadAttributes;
481 // thread attributes to be used when
482 // constructing processing threads
483
484 const int d_maxThreads; // maximum number of processing
485 // threads that can be started at
486 // any given time by this thread
487 // pool
488
489 const int d_minThreads; // minimum number of processing
490 // threads that must running at any
491 // given time
492
493 int d_threadCount; // current number of processing
494 // threads started by this thread
495 // pool
496
497 bsls::AtomicInt d_createFailures; // number of thread create failures
498
499
500 bsls::TimeInterval d_maxIdleTime; // time that threads (in excess of
501 // the minimum number of threads)
502 // remain idle before being shut
503 // down
504
505 int d_numActiveThreads;
506 // current number of threads that
507 // are actively processing a job
508
509 bsls::AtomicInt d_enabled; // indicates the enabled state of
510 // queue; queuing is disabled when
511 // 0, enabled otherwise
512
514 d_waitHead; // pointer to the 'WaitNode' control
515 // structure of the first thread
516 // that is waiting for a request
517
518 bsls::AtomicInt64 d_lastResetTime; // last reset time of percent-busy
519 // metric in nanoseconds from some
520 // arbitrary but fixed point in time
521
522 bsls::AtomicInt64 d_callbackTime; // the total time spent running jobs
523 // (callbacks) across all threads,
524 // in nanoseconds
525
526 bsls::AtomicInt64 d_numThreadCreateFailures;
527 // count of thread creation failures
528
529#if defined(BSLS_PLATFORM_OS_UNIX)
530 sigset_t d_blockSet; // set of signals to be blocked in
531 // managed threads
532#endif
533
535 d_backlogHandle; // backlog metric handle
536
537 // CLASS DATA
538 static const char s_defaultThreadName[16]; // default name of threads
539 // if supported and
540 // attributes doesn't
541 // specify another name
542
543 // FRIENDS
544 friend void* ThreadPoolEntry(void *);
545
546 // PRIVATE MANIPULATORS
547
548 /// Internal method used to push the specified `job` onto `d_queue` and signal the next waiting thread if any.
549 ///
550 /// \note Note that this method must
551 /// be called with `d_mutex` locked.
552 void doEnqueueJob(const Job& job);
553 void doEnqueueJob(bslmf::MovableRef<Job> job);
554
555 /// Initialize this thread pool using the stored attributes and the
556 /// specified `metricsRegistry` and `threadPoolName`. If
557 /// `metricsRegistry` is 0, `bdlm::MetricsRegistry::singleton()` is
558 /// used.
559 void initialize(bdlm::MetricsRegistry *metricsRegistry,
560 const bsl::string_view& threadPoolName);
561
562 /// Signal this thread and pop the current thread from the wait list.
563 void wakeThreadIfNeeded();
564
565 /// Start a new thread if needed and the maximum number of threads are
566 /// not yet running. This method must be called with `d_mutex` locked.
567 /// Return 0 if at least one thread is running, and a non-zero value
568 /// otherwise.
569 int startThreadIfNeeded();
570
571#if defined(BSLS_PLATFORM_OS_UNIX)
572 /// Initialize the set of signals to be blocked in the managed threads.
573 void initBlockSet();
574#endif
575
576 /// Internal method to spawn a new processing thread and increment the
577 /// current count. This method must be called with `d_mutex` locked.
578 int startNewThread();
579
580 /// Processing thread function.
581 void workerThread();
582
583 private:
584 // NOT IMPLEMENTED
585 ThreadPool(const ThreadPool&);
586 ThreadPool& operator=(const ThreadPool&);
587
588 public:
589 // TRAITS
591
592 // CREATORS
593
594 /// Construct a thread pool with the specified `threadAttributes`, the
595 /// specified `minThreads` minimum number of threads, the specified
596 /// `maxThreads` maximum number of threads, and the specified
597 /// `maxIdleTime` idle time (in milliseconds) after which a thread may
598 /// be considered for destruction. Optionally specify a
599 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
600 /// the currently installed default allocator is used. The name used for
601 /// created threads is `threadAttributes.threadName()` if not empty, otherwise "bdl.ThreadPool".
602 ///
603 /// \pre The behavior is undefined unless
604 /// `0 <= minThreads`, `minThreads <= maxThreads`, and `0 <= maxIdleTime`.
605 ThreadPool(const bslmt::ThreadAttributes& threadAttributes,
606 int minThreads,
607 int maxThreads,
608 int maxIdleTime,
609 bslma::Allocator *basicAllocator = 0);
610
611 /// Construct a thread pool with the specified `threadAttributes`, the
612 /// specified `minThreads` minimum number of threads, the specified
613 /// `maxThreads` maximum number of threads, the specified `maxIdleTime`
614 /// idle time (in milliseconds) after which a thread may be considered
615 /// for destruction, the specified `threadPoolName` to be used to
616 /// identify this thread pool, and the specified `metricsRegistry` to
617 /// be used for reporting metrics. If `metricsRegistry` is 0,
618 /// `bdlm::MetricsRegistry::singleton()` is used. Optionally specify a
619 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
620 /// the currently installed default allocator is used. The name used for
621 /// created threads is `threadAttributes.threadName()` if not empty,
622 /// otherwise `threadPoolName` if not empty, otherwise "bdl.ThreadPool".
623 ///
624 /// \pre The behavior is undefined unless `0 <= minThreads`,
625 /// `minThreads <= maxThreads`, and `0 <= maxIdleTime`.
626 ThreadPool(const bslmt::ThreadAttributes& threadAttributes,
627 int minThreads,
628 int maxThreads,
629 int maxIdleTime,
630 const bsl::string_view& threadPoolName,
631 bdlm::MetricsRegistry *metricsRegistry,
632 bslma::Allocator *basicAllocator = 0);
633
634 /// Construct a thread pool with the specified `threadAttributes`, the
635 /// specified `minThreads` minimum number of threads, the specified
636 /// `maxThreads` maximum number of threads, and the specified
637 /// `maxIdleTime` idle time after which a thread may be considered for
638 /// destruction. Optionally specify a `basicAllocator` used to supply
639 /// memory. If `basicAllocator` is 0, the currently installed default
640 /// allocator is used. The name used for created threads is
641 /// `threadAttributes.threadName()` if not empty, otherwise "bdl.ThreadPool".
642 ///
643 /// \pre The behavior is undefined unless `0 <= minThreads`,
644 /// `minThreads <= maxThreads`, `0 <= maxIdleTime`, and the `maxIdleTime`
645 /// has a value less than or equal to `INT_MAX` milliseconds.
646 ThreadPool(const bslmt::ThreadAttributes& threadAttributes,
647 int minThreads,
648 int maxThreads,
650 bslma::Allocator *basicAllocator = 0);
651
652 /// Construct a thread pool with the specified `threadAttributes`, the
653 /// specified `minThreads` minimum number of threads, the specified
654 /// `maxThreads` maximum number of threads, the specified `maxIdleTime`
655 /// idle time after which a thread may be considered for destruction,
656 /// the specified `threadPoolName` to be used to identify this thread
657 /// pool, and the specified `metricsRegistry` to be used for reporting
658 /// metrics. If `metricsRegistry` is 0,
659 /// `bdlm::MetricsRegistry::singleton()` is used. Optionally specify a
660 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
661 /// the currently installed default allocator is used. The name used for
662 /// created threads is `threadAttributes.threadName()` if not empty,
663 /// otherwise `threadPoolName` if not empty, otherwise "bdl.ThreadPool".
664 ///
665 /// \pre The behavior is undefined unless `0 <= minThreads`,
666 /// `minThreads <= maxThreads`, `0 <= maxIdleTime`, and the `maxIdleTime`
667 /// has a value less than or equal to `INT_MAX` milliseconds.
668 ThreadPool(const bslmt::ThreadAttributes& threadAttributes,
669 int minThreads,
670 int maxThreads,
672 const bsl::string_view& threadPoolName,
673 bdlm::MetricsRegistry *metricsRegistry,
674 bslma::Allocator *basicAllocator = 0);
675
676 /// Call `shutdown()` and destroy this thread pool.
678
679 // MANIPULATORS
680
681 /// Disable queuing on this thread pool and wait until all pending jobs
682 /// complete. Use `start` to re-enable queuing.
683 void drain();
684
685 /// Enqueue the specified `functor` to be executed by the next available
686 /// thread. Return 0 if enqueued successfully, and a non-zero value if queuing is currently disabled.
687 ///
688 /// \pre The behavior is undefined unless
689 /// `functor` is not "unset". See `bsl::function` for more information
690 /// on functors.
691 int enqueueJob(const Job& functor);
693
694 /// Enqueue the specified `function` to be executed by the next
695 /// available thread. The specified `userData` pointer will be passed
696 /// to the function by the processing thread. Return 0 if enqueued
697 /// successfully, and a non-zero value if queuing is currently disabled.
698 int enqueueJob(ThreadPoolJobFunc function, void *userData);
699
700 /// Atomically report the percentage of wall time spent by each thread of
701 /// this thread pool executing jobs since the last reset time, and set the
702 /// reset time to now. The creation of the thread pool is considered a
703 /// first reset time. This value is calculated as:
704 /// @code
705 /// sum(jobExecutionTime) 100%
706 /// P_busy = -------------------- x ----------
707 /// timeSinceLastReset maxThreads
708 /// @endcode
709 ///
710 /// \note Note that this percentage reflects the wall time spent per thread, and
711 /// not CPU time per thread, or not even CPU time per processor. Also note
712 /// that there is no guarantee that all threads are processed concurrently
713 /// (e.g., the number of threads could be larger than the number of
714 /// processors).
716
717 /// Disable queuing on this thread pool, cancel all queued jobs, and shut
718 /// down all processing threads (after all active jobs complete).
719 void shutdown();
720
721 /// Enable queuing on this thread pool and spawn `minThreads()` processing
722 /// threads. Return 0 on success, and a non-zero value otherwise. If
723 /// `minThreads()` threads were not successfully started, all threads are
724 /// stopped.
725 int start();
726
727 /// Disable queuing on this thread pool and wait until all pending jobs
728 /// complete, then shut down all processing threads.
729 void stop();
730
731 // ACCESSORS
732
733 /// Return the state (enabled or not) of the thread pool.
734 int enabled() const;
735
736 /// Return the maximum number of threads that are allowed to be running at
737 /// given time.
738 int maxThreads() const;
739
740 /// Return the amount of time (in milliseconds) a thread remains idle
741 /// before being shut down when there are more than min threads started.
742 int maxIdleTime() const;
743
744 /// Return the amount of time a thread remains idle before being shut down
745 /// when there are more than min threads started.
747
748 /// Return the minimum number of threads that must be started at any given
749 /// time.
750 int minThreads() const;
751
752 /// Return the number of threads that are currently processing a job.
753 int numActiveThreads() const;
754
755 /// Return the number of jobs that are currently queued, but not yet being
756 /// processed.
757 int numPendingJobs() const;
758
759 /// Return the number of threads that are currently waiting for a job.
760 int numWaitingThreads() const;
761
762 /// Return the percentage of wall time spent by each thread of this thread
763 /// pool executing jobs since the last reset time. The creation of the
764 /// thread pool is considered a first reset time. This value is calculated
765 /// as:
766 /// @code
767 /// sum(jobExecutionTime) 100%
768 /// P_busy = -------------------- x ----------
769 /// timeSinceLastReset maxThreads
770 /// @endcode
771 ///
772 /// \note Note that this percentage reflects the wall time spent per thread, and
773 /// not CPU time per thread, or not even CPU time per processor. Also note
774 /// that there is no guarantee that all threads are processed concurrently
775 /// (e.g., the number of threads could be larger than the number of
776 /// processors).
777 double percentBusy() const;
778
779 /// Return the number of times that thread creation failed.
780 int threadFailures() const;
781};
782
783// ============================================================================
784// INLINE DEFINITIONS
785// ============================================================================
786
787// MANIPULATORS
788
789inline
790int ThreadPool::enqueueJob(ThreadPoolJobFunc function, void *userData)
791{
792 return enqueueJob(bdlf::BindUtil::bindR<void>(function, userData));
793}
794
795// ACCESSORS
796
797inline
799{
800 return d_enabled;
801}
802
803inline
805{
806 return d_minThreads;
807}
808
809inline
811{
812 return d_maxThreads;
813}
814
815inline
817{
818 return d_createFailures;
819}
820
821inline
823{
824 return static_cast<int>(d_maxIdleTime.totalMilliseconds());
825}
826
827inline
829{
830 return d_maxIdleTime;
831}
832
833} // close package namespace
834
835#endif
836
837// ----------------------------------------------------------------------------
838// Copyright 2024 Bloomberg Finance L.P.
839//
840// Licensed under the Apache License, Version 2.0 (the "License");
841// you may not use this file except in compliance with the License.
842// You may obtain a copy of the License at
843//
844// http://www.apache.org/licenses/LICENSE-2.0
845//
846// Unless required by applicable law or agreed to in writing, software
847// distributed under the License is distributed on an "AS IS" BASIS,
848// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
849// See the License for the specific language governing permissions and
850// limitations under the License.
851// ----------------------------- END-OF-FILE ----------------------------------
852
853/** @} */
854/** @} */
855/** @} */
Definition bdlm_metricsregistry.h:306
Definition bdlm_metricsregistry.h:197
Definition bdlmt_threadpool.h:461
double percentBusy() const
bsl::function< void()> Job
Definition bdlmt_threadpool.h:465
int threadFailures() const
Return the number of times that thread creation failed.
Definition bdlmt_threadpool.h:816
int enqueueJob(const Job &functor)
ThreadPool(const bslmt::ThreadAttributes &threadAttributes, int minThreads, int maxThreads, int maxIdleTime, bslma::Allocator *basicAllocator=0)
int maxThreads() const
Definition bdlmt_threadpool.h:810
int enqueueJob(bslmf::MovableRef< Job > functor)
ThreadPool(const bslmt::ThreadAttributes &threadAttributes, int minThreads, int maxThreads, bsls::TimeInterval maxIdleTime, const bsl::string_view &threadPoolName, bdlm::MetricsRegistry *metricsRegistry, bslma::Allocator *basicAllocator=0)
int minThreads() const
Definition bdlmt_threadpool.h:804
int numPendingJobs() const
BSLMF_NESTED_TRAIT_DECLARATION(ThreadPool, bslma::UsesBslmaAllocator)
ThreadPool(const bslmt::ThreadAttributes &threadAttributes, int minThreads, int maxThreads, bsls::TimeInterval maxIdleTime, bslma::Allocator *basicAllocator=0)
bsls::TimeInterval maxIdleTimeInterval() const
Definition bdlmt_threadpool.h:828
int maxIdleTime() const
Definition bdlmt_threadpool.h:822
int numWaitingThreads() const
Return the number of threads that are currently waiting for a job.
int numActiveThreads() const
Return the number of threads that are currently processing a job.
friend void * ThreadPoolEntry(void *)
Entry point for processing threads.
int enabled() const
Return the state (enabled or not) of the thread pool.
Definition bdlmt_threadpool.h:798
double resetPercentBusy()
ThreadPool(const bslmt::ThreadAttributes &threadAttributes, int minThreads, int maxThreads, int maxIdleTime, const bsl::string_view &threadPoolName, bdlm::MetricsRegistry *metricsRegistry, bslma::Allocator *basicAllocator=0)
~ThreadPool()
Call shutdown() and destroy this thread pool.
Definition bslstl_stringview.h:471
Definition bslstl_deque.h:814
Forward declaration.
Definition bslstl_function.h:946
Definition bslma_allocator.h:545
Definition bslmf_movableref.h:752
Definition bslmt_condition.h:220
Definition bslmt_mutex.h:317
Definition bslmt_threadattributes.h:361
Definition bsls_atomic.h:896
Definition bsls_atomic.h:744
Definition bsls_atomic.h:1362
Definition bsls_timeinterval.h:307
BSLS_KEYWORD_CONSTEXPR_CPP14 bsls::Types::Int64 totalMilliseconds() const
Definition bsls_timeinterval.h:1459
void(* bcep_ThreadPoolJobFunc)(void *)
Definition bdlmt_threadpool.h:438
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlmt_eventscheduler.h:550
void(* ThreadPoolJobFunc)(void *)
Definition bdlmt_threadpool.h:451
void * ThreadPoolEntry(void *)
Entry point for processing threads.
Definition bslma_usesbslmaallocator.h:344