BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlmt_multiprioritythreadpool.h
Go to the documentation of this file.
1/// @file bdlmt_multiprioritythreadpool.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlmt_multiprioritythreadpool.h -*-C++-*-
8#ifndef INCLUDED_BDLMT_MULTIPRIORITYTHREADPOOL
9#define INCLUDED_BDLMT_MULTIPRIORITYTHREADPOOL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlmt_multiprioritythreadpool bdlmt_multiprioritythreadpool
15/// @brief Provide a mechanism to parallelize a prioritized sequence of jobs.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlmt
19/// @{
20/// @addtogroup bdlmt_multiprioritythreadpool
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlmt_multiprioritythreadpool-purpose"> Purpose</a>
25/// * <a href="#bdlmt_multiprioritythreadpool-classes"> Classes </a>
26/// * <a href="#bdlmt_multiprioritythreadpool-description"> Description </a>
27/// * <a href="#bdlmt_multiprioritythreadpool-thread-safety"> Thread Safety </a>
28/// * <a href="#bdlmt_multiprioritythreadpool-thread-names-for-sub-threads"> Thread Names for Sub-Threads </a>
29/// * <a href="#bdlmt_multiprioritythreadpool-usage"> Usage </a>
30/// * <a href="#bdlmt_multiprioritythreadpool-example-1-the-void-functionvoid-pointer-interface"> Example 1: The void functionvoid pointer Interface </a>
31/// * <a href="#bdlmt_multiprioritythreadpool-example-2-the-functor-based-interface"> Example 2: The Functor-Based Interface </a>
32///
33/// # Purpose {#bdlmt_multiprioritythreadpool-purpose}
34/// Provide a mechanism to parallelize a prioritized sequence of jobs.
35///
36/// # Classes {#bdlmt_multiprioritythreadpool-classes}
37///
38/// - bdlmt::MultipriorityThreadPool: mechanism to parallelize prioritized jobs
39///
40/// @see bslmt_threadutil
41///
42/// # Description {#bdlmt_multiprioritythreadpool-description}
43/// This component defines an implementation of a thread pool in
44/// which work items ("jobs") are associated with a limited number of integer
45/// priorities that determine the sequence in which enqueued jobs are executed.
46/// (See the package-level documentation for general information on thread
47/// pools.)
48///
49/// This flavor of our generalized thread pool model associates an integral
50/// priority with each work item. For efficiency of implementation, these
51/// priorities are limited, as indicated at construction, to a relatively small
52/// number `N` of contiguous integers `[ 0 .. N - 1 ]`, 0 being the most urgent.
53/// For this implementation, the maximum number of priorities `N` is 32. A
54/// fixed number of worker threads is also specified at construction. Finally,
55/// this thread pool takes an optional allocator supplied at construction.
56/// Once configured, these instance parameters remain unchanged for the lifetime
57/// of each multi-priority thread pool object.
58///
59/// The associated priority of a job is relevant only while that job is pending;
60/// once a job has begun executing, it will not be interrupted or suspended to
61/// make way for a another job regardless of their relative priorities. While
62/// processing jobs, worker threads will always choose a more urgent job (lower
63/// integer value for priority) over a less urgent one. Given two jobs having
64/// the same priority value, the one that has been in the thread pool's queue
65/// the longest is selected (FIFO order). Note that the number of active worker
66/// threads does not increase or decrease depending on load. If no jobs remain
67/// to be executed, surplus threads will block until work arrives. If there are
68/// more jobs than threads, excess jobs wait in the queue until previous jobs
69/// finish.
70///
71/// `bdlmt::MultipriorityThreadPool` provides two interfaces for specifying
72/// jobs: the traditional `void function`/`void pointer` interface and the more
73/// versatile functor-based interface. The `void function`/`void pointer`
74/// interface allows callers to use a C-style function to be executed as a job.
75/// The application need specify only the address of the function, and a single
76/// `void *` argument to be passed to the function. The specified function will
77/// be invoked with the specified argument by the processing (worker) thread.
78/// The functor-based interface allows for flexible job execution by copying the
79/// passed functor and executing its (invokable) `operator()` method. Note that
80/// the functor gets copied twice before it is executed, once when pushed into
81/// the queue, and once when popped out of it, something to keep in mind if the
82/// object is going to be expensive to copy. (See the `bdef` package-level
83/// documentation for more information on functors and their use.)
84///
85/// Note that except in the case where `numThreads() == 1`, we cannot guarantee
86/// the exact order of the execution of the jobs in the queue.
87///
88/// Finally an application can specify the attributes of the worker threads in a
89/// thread pool (e.g., guard size or stack size), by optionally supplying an
90/// appropriately configured `bslmt::ThreadAttributes` object. (See the
91/// @ref bslmt_threadutil component-level documentation for a description of the
92/// `bslmt::ThreadAttributes` class.) Note that the field pertaining to whether
93/// the worker threads should be detached or joinable is ignored.
94///
95/// ## Thread Safety {#bdlmt_multiprioritythreadpool-thread-safety}
96///
97///
98/// The `bdlmt::MultipriorityThreadPool` class is both *fully thread-safe*
99/// (i.e., all non-creator methods can correctly execute concurrently), and is
100/// *thread-enabled* (i.e., the classes does not function correctly in a
101/// non-multi-threading environment). See @ref bsldoc_glossary for complete
102/// definitions of *fully thread-safe* and *thread-enabled*.
103///
104/// Be aware that the behavior is undefined if any of the following methods are
105/// called on a threadpool from any of the threads belonging to that thread
106/// pool.
107/// * `stopThreads`
108/// * `suspendProcessing`
109/// * `drainJobs`
110/// Note that, in these cases, such undefined behavior may include deadlock.
111///
112/// ## Thread Names for Sub-Threads {#bdlmt_multiprioritythreadpool-thread-names-for-sub-threads}
113///
114///
115/// To facilitate debugging, users can provide a thread name as the `threadName`
116/// attribute of the `bslmt::ThreadAttributes` argument passed to the
117/// constructor, that will be used for all the sub-threads. The thread name
118/// should not be used programmatically, but will appear in debugging tools on
119/// platforms that support naming threads to help users identify the source and
120/// purpose of a thread. If no `ThreadAttributes` object is passed, or if the
121/// `threadName` attribute is not set, the default value "bdl.MultiPriPl" will
122/// be used.
123///
124/// ## Usage {#bdlmt_multiprioritythreadpool-usage}
125///
126///
127/// This section illustrates intended use of this component.
128///
129/// ### Example 1: The void functionvoid pointer Interface {#bdlmt_multiprioritythreadpool-example-1-the-void-functionvoid-pointer-interface}
130///
131///
132/// It is possible to enqueue a job to a multi-priority thread pool as a pointer
133/// to a function that takes a single `void *` argument. This first usage
134/// example will demonstrate that high-priority traffic through a thread pool is
135/// unimpeded by a much greater quantity of low-priority traffic.
136///
137/// The idea here is we have a large number of jobs submitted in too little time
138/// for all of them to be completed. All jobs take the same amount of time to
139/// complete, but there are two different priorities of jobs. There are 100
140/// times more jobs of less urgent priority than of the more urgent priority,
141/// and there is more than enough time for the jobs of more urgent priority to
142/// be completed. We want to verify that all the jobs of more urgent priority
143/// get completed while most of the jobs of less urgent priority do not. This
144/// will demonstrate that we can construct an arrangement where traffic of low
145/// priority, while massively more numerous, does not impede the progress of
146/// higher-priority jobs:
147/// @code
148/// bsls::AtomicInt urgentJobsDone;
149/// bsls::AtomicInt lessUrgentJobsDone;
150///
151/// inline
152/// extern "C" void *urgentJob(void *)
153/// {
154/// bslmt::ThreadUtil::microSleep(10000); // 10 mSec
155///
156/// ++urgentJobsDone;
157///
158/// return 0;
159/// }
160///
161/// extern "C" void *lessUrgentJob(void *)
162/// {
163/// bslmt::ThreadUtil::microSleep(10000); // 10 mSec
164///
165/// ++lessUrgentJobsDone;
166///
167/// return 0;
168/// }
169/// @endcode
170/// The main program (below) enqueues 100 times as many low-priority jobs as
171/// high priority ones. 10,100 jobs are submitted, each taking at least 0.01
172/// seconds, for a total cpu time of 101 seconds. We use 20 threads, so that
173/// is about 5 seconds. But we shut down the run after only 0.5 seconds, so
174/// that means at least 90% of the jobs will not complete. When run, typical
175/// output of this program is:
176/// @code
177/// Jobs done: urgent: 100, less urgent: 507
178/// @endcode
179/// meaning *all* of the urgent jobs completed, while approximately 95% of the
180/// less urgent jobs did not:
181/// @code
182/// bdlmt::MultipriorityThreadPool pool(20, // # of threads
183/// 2); // # of priorities
184///
185/// bsls::TimeInterval finishTime =
186/// bsls::SystemTime::nowRealtimeClock() + 0.5;
187/// pool.startThreads();
188/// @endcode
189/// We use 1 as our less urgent priority, leaving 0 as our urgent priority:
190/// @code
191/// for (int i = 0; i < 100; ++i) {
192/// for (int j = 0; j < 100; ++j) {
193/// pool.enqueueJob(&lessUrgentJob, (void *) 0, 1); // less urgent
194/// }
195/// pool.enqueueJob(&urgentJob, (void *) 0, 0); // urgent
196/// }
197///
198/// bslmt::ThreadUtil::sleepUntil(finishTime);
199/// pool.shutdown();
200///
201/// bsl::cout << "Jobs done: urgent: " << urgentJobsDone <<
202/// ", less urgent: " << lessUrgentJobsDone << bsl::endl;
203/// @endcode
204///
205/// ### Example 2: The Functor-Based Interface {#bdlmt_multiprioritythreadpool-example-2-the-functor-based-interface}
206///
207///
208/// In this second example we present a multi-threaded algorithm for calculating
209/// prime numbers. This is just to serve as an illustration; although it works,
210/// it is not really any faster than doing it with a single thread.
211///
212/// For every prime number `P`, we have to mark all multiples of it in two
213/// ranges, `[ P .. P ** 2 ]` and `[ P ** 2 .. TOP_NUMBER ]`, as non-prime,
214/// where we use 2000 for `TOP_NUMBER` in this example. For any `P ** 2`, if we
215/// can determine that all primes below `P` have marked all their multiples up
216/// to `P ** 2`, then we can scan that range and any unmarked values in it will
217/// be a new prime. The we can start out with our first prime, 2, and mark all
218/// primes between it and `2 ** 2 == 4`, thus discovering 3 is prime. Once we
219/// have marked all multiples of 2 and 3 below `3 * 3 == 9`, we can then scan
220/// that range and discover 5 and 7 are primes, and repeat the process to
221/// discover bigger and bigger primes until we have covered an entire range (in
222/// this example all ints below TOP_NUMBER == 2000):
223/// @code
224/// enum {
225/// TOP_NUMBER = 2000,
226/// NUM_PRIORITIES = 32
227/// };
228///
229/// bool isStillPrime[TOP_NUMBER];
230/// bsls::AtomicInt scannedTo[TOP_NUMBER]; // if `P` is a prime, what is the
231/// // highest multiple of `P` that
232/// // we have marked
233/// // `isStillPrime[P] = false`
234///
235/// bsls::AtomicInt maxPrimeFound; // maximum prime identified so far
236/// int primeNumbers[TOP_NUMBER]; // elements in the range
237/// // `0 .. numPrimeNumbers - 1` are
238/// // the prime numbers we have found
239/// // so far
240/// bsls::AtomicInt numPrimeNumbers;
241///
242/// bdlmt::MultipriorityThreadPool *threadPool;
243///
244/// bool doneFlag; // set this flag to signal
245/// // other jobs that we're done
246/// bslmt::Barrier doneBarrier(2); // we wait on this barrier
247/// // to signal the main thread
248/// // that we're done
249///
250/// struct Functor {
251/// static bslmt::Mutex s_mutex;
252/// int d_numToScan;
253/// int d_priority;
254/// int d_limit;
255///
256/// Functor(int numToScan)
257/// : d_numToScan(numToScan)
258/// , d_priority(0)
259/// {
260/// d_limit = bsl::min((double) numToScan * numToScan,
261/// (double) TOP_NUMBER);
262/// }
263///
264/// void setNewPrime(int newPrime) {
265/// maxPrimeFound = newPrime;
266/// primeNumbers[numPrimeNumbers] = newPrime;
267/// ++numPrimeNumbers;
268///
269/// if (2 * newPrime < TOP_NUMBER) {
270/// Functor f(newPrime);
271///
272/// threadPool->enqueueJob(f, 0);
273/// }
274/// }
275///
276/// void evaluateCandidatesForPrime() {
277/// if (maxPrimeFound > d_limit) {
278/// return;
279/// }
280///
281/// int numToScanI;
282/// for (numToScanI = numPrimeNumbers - 1; numToScanI > 0;
283/// --numToScanI) {
284/// if (primeNumbers[numToScanI] == d_numToScan) {
285/// break;
286/// }
287/// }
288/// for (int i = numToScanI - 1; i < 0; --i) {
289/// if (TOP_NUMBER < scannedTo[primeNumbers[i]]) {
290/// for (int j = i + 1; j < numPrimeNumbers; ++j) {
291/// if (TOP_NUMBER == scannedTo[primeNumbers[j]]) {
292/// scannedTo[primeNumbers[j]] = TOP_NUMBER + 1;
293/// }
294/// else {
295/// break;
296/// }
297/// }
298/// break;
299/// }
300///
301/// if (scannedTo[primeNumbers[i]] < d_limit) {
302/// // Not all multiples of all prime numbers below
303/// // us have been adequately marked as non-prime. We
304/// // cannot yet draw any new conclusions about what
305/// // is and what is not prime in this range.
306///
307/// // Resubmit ourselves to the back of the priority queue
308/// // so that we'll get re-evaluated when previous prime
309/// // numbers are done scanning. Note that we could get
310/// // reenqueued several times.
311///
312/// // Note that jobs marking the 'isStillPrime' array are
313/// // at priority 0, while later incarnations that can
314/// // only set new primes are at priority 1 and keep
315/// // getting resubmitted at less and less urgent
316/// // priorities until all their prerequisites (which
317/// // are at priority 0) are done.
318///
319/// d_priority = bsl::min(NUM_PRIORITIES - 2,
320/// d_priority + 1);
321/// threadPool->enqueueJob(*this, d_priority);
322///
323/// return;
324/// }
325/// }
326///
327/// // Everything up to 'd_limit' that has not been marked
328/// // non-prime is prime.
329///
330/// bslmt::LockGuard<bslmt::Mutex> guard(&s_mutex);
331///
332/// for (int i = maxPrimeFound + 1; d_limit > i; ++i) {
333/// if (isStillPrime[i]) {
334/// setNewPrime(i);
335/// }
336/// }
337///
338/// if (TOP_NUMBER == d_limit && !doneFlag) {
339/// // We have successfully listed all primes below 'TOP_NUMBER'.
340/// // Touch the done barrier and our caller will then know that
341/// // we are done and shut down the queue.
342///
343/// doneFlag = true;
344/// doneBarrier.wait();
345/// }
346/// }
347///
348/// void operator()() {
349/// if (0 == d_priority) {
350/// bsls::AtomicInt& rScannedTo = scannedTo[d_numToScan];
351///
352/// for (int i = d_numToScan; i < d_limit; i += d_numToScan) {
353/// isStillPrime[i] = false;
354/// rScannedTo = i;
355/// }
356///
357/// d_priority = 1;
358/// threadPool->enqueueJob(*this, d_priority);
359///
360/// for (int i = d_limit; i < TOP_NUMBER; i += d_numToScan) {
361/// isStillPrime[i] = false;
362/// rScannedTo = i;
363/// }
364/// rScannedTo = TOP_NUMBER;
365/// }
366/// else {
367/// evaluateCandidatesForPrime();
368/// }
369/// }
370/// };
371/// bslmt::Mutex Functor::s_mutex;
372/// @endcode
373/// and in the main program:
374/// @code
375/// bsls::TimeInterval startTime = bsls::SystemTime::nowRealtimeClock();
376///
377/// for (int i = 0; TOP_NUMBER > i; ++i) {
378/// isStillPrime[i] = true;
379/// scannedTo[i] = 0;
380/// }
381///
382/// scannedTo[0] = TOP_NUMBER + 1;
383/// scannedTo[1] = TOP_NUMBER + 1;
384///
385/// maxPrimeFound = 2;
386/// primeNumbers[0] = 2;
387/// numPrimeNumbers = 1;
388/// doneFlag = false;
389///
390/// threadPool =
391/// new (ta) bdlmt::MultipriorityThreadPool(20, NUM_PRIORITIES, &ta);
392/// threadPool->startThreads();
393///
394/// bsls::TimeInterval startJobs = bsls::SystemTime::nowRealtimeClock();
395///
396/// Functor f(2);
397/// threadPool->enqueueJob(f, 0);
398///
399/// doneBarrier.wait();
400///
401/// bsls::TimeInterval finish = bsls::SystemTime::nowRealtimeClock();
402///
403/// threadPool->shutdown();
404/// ta.deleteObjectRaw(threadPool);
405///
406/// if (verbose) {
407/// bsls::TimeInterval endTime = bsls::SystemTime::nowRealtimeClock();
408///
409/// double elapsed = (endTime - startTime).totalSecondsAsDouble();
410/// double elapsedNoInit = (finish - startJobs).totalSecondsAsDouble();
411///
412/// printf("Runtime: %g seconds, %g seconds w/o init & cleanup\n",
413/// elapsed, elapsedNoInit);
414///
415/// printf("%d prime numbers below %d:", (int) numPrimeNumbers,
416/// TOP_NUMBER);
417///
418/// for (int i = 0; numPrimeNumbers > i; ++i) {
419/// printf("%s%4d", 0 == i % 10 ? "\n " : ", ",
420/// primeNumbers[i]);
421/// }
422/// printf("\n");
423/// }
424/// @endcode
425/// @}
426/** @} */
427/** @} */
428
429/** @addtogroup bdl
430 * @{
431 */
432/** @addtogroup bdlmt
433 * @{
434 */
435/** @addtogroup bdlmt_multiprioritythreadpool
436 * @{
437 */
438
439#include <bdlscm_version.h>
440
442
444
446
447#include <bslmt_mutex.h>
449#include <bslmt_threadutil.h>
450#include <bslmt_threadgroup.h>
451
452#include <bsls_atomic.h>
453
454#include <bslma_allocator.h>
455
456#include <bsls_platform.h>
457
458#include <bsl_climits.h>
459
460#if defined(BSLS_PLATFORM_OS_UNIX)
461 #include <bsl_c_signal.h>
462#endif
463#include <bsl_functional.h>
464
465
466
467namespace bdlmt {
468 // =============================
469 // class MultipriorityThreadPool
470 // =============================
471
472/// This class implements a thread-enabled, integrally-prioritized
473/// thread-pool mechanism used for concurrently executing multiple
474/// user-defined "jobs" supplied as either conventional C-style functions
475/// taking an optional `void *` data argument, or as more flexible functor
476/// objects.
477///
478/// See @ref bdlmt_multiprioritythreadpool
480
481 public:
482 // TYPES
483
484 /// `ThreadFunctor` is an alias for a function object that is invokable
485 /// (with no arguments) and returns `void`; its use is similar to that
486 /// of a C-style function pointer and optional `void *` data pointer
487 /// passed as arguments when creating a thread.
489
490 enum {
491 k_MAX_NUM_PRIORITIES = sizeof(int) * CHAR_BIT // bits per 'int'
492#ifndef BDE_OMIT_INTERNAL_DEPRECATED
495#endif // BDE_OMIT_INTERNAL_DEPRECATED
496 };
497
498 private:
499 // PRIVATE CLASS DATA
500 static const char s_defaultThreadName[16];// Thread name to use when
501 // none is specified.
502
503 // PRIVATE DATA
504 bslmt::Mutex d_mutex; // mutex for worker threads as they
505 // analyze state, and for methods
506 // that manipulate that state
507
508 bslmt::Mutex d_metaMutex; // mutex for '[start|stop]Threads',
509 // '[suspend|resume]Processing',
510 // 'drainJobs'; this mutex gets
511 // locked much less frequently than
512 // 'd_mutex', but for longer periods
513 // of time
514
516 d_queue; // pending job queue
517
518 bslmt::ThreadAttributes d_threadAttributes;
519 // user-supplied attributes of all
520 // the threads this pool spawns
521
522 bslmt::ThreadGroup d_threadGroup;
523 // thread group managing our threads
524
525 const int d_numThreads;
526 // user-supplied number of threads
527 // to be used to process jobs
528
529 bsls::AtomicInt d_threadStartState;
530 // enum of type 'StartState' (local
531 // to .cpp) regarding whether threads
532 // are started
533
534 bsls::AtomicInt d_threadSuspendState;
535 // enum of type 'ResumeState' (local
536 // to .cpp) regarding whether threads
537 // are suspended
538
539 bsls::AtomicInt d_numStartedThreads;
540 // number of threads currently
541 // started
542
543 bsls::AtomicInt d_numSuspendedThreads;
544 // number of threads currently
545 // suspended
546
547 bsls::AtomicInt d_numActiveThreads;
548 // number of threads currently
549 // processing jobs
550
551 bslmt::Condition d_allThreadsStartedCondition;
552 // broadcast when number of started
553 // threads reaches 'd_numThreads',
554 // watched during starting
555
556 bslmt::Condition d_allThreadsSuspendedCondition;
557 // broadcast when number of started
558 // threads reaches 'd_numThreads',
559 // watched during starting
560
561 bslmt::Condition d_resumeCondition;
562 // broadcast when suspended threads
563 // are to resume
564
565 private:
566 // NOT IMPLEMENTED
569
570 // PRIVATE MANIPULATORS
571
572 /// This method runs in each thread of this multi-priority thread pool,
573 /// processing jobs until commanded to stop, in which case the thread
574 /// exits to be joined.
575 void worker();
576
577 public:
578 // TRAITS
581
582 // CREATORS
583
585 int numPriorities,
586 bslma::Allocator *basicAllocator = 0);
587 /// Create a multi-priority thread pool capable of concurrently
588 /// executing the specified `numThreads` "jobs" with associated integer
589 /// priorities in the specified range `[0 .. numPriorities - 1]`, 0
590 /// being the most urgent. Optionally specify `threadAttributes` used
591 /// to customize each worker thread created by this thread pool, in
592 /// which case the attribute pertaining to whether the worker threads
593 /// are created in the detached state is ignored. Optionally specify a
594 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
595 /// the currently installed default allocator is used. The newly
596 /// created thread pool will initially be enabled for enqueuing jobs,
597 /// but with no worker threads created. The behavior is undefined
598 /// unless `1 <= numThreads` and
599 /// `1 <= numPriorities <= k_MAX_NUM_PRIORITIES`.
601 int numThreads,
602 int numPriorities,
603 const bslmt::ThreadAttributes& threadAttributes,
604 bslma::Allocator *basicAllocator = 0);
605
606 /// Remove (cancel) all pending jobs and destroy this multi-priority
607 /// thread pool. The behavior is undefined unless this thread pool is
608 /// stopped.
610
611 // MANIPULATORS
612
613 /// Add the specified `job` to the queue of this multi-priority thread
614 /// pool, assigning it the specified `priority`. Return 0 if the job
615 /// was enqueued successfully, and a non-zero value otherwise (implying
616 /// that the queue was in the disabled state). The behavior is
617 /// undefined unless `0 <= priority < numPriorities()`.
618 int enqueueJob(const ThreadFunctor& job, int priority);
619
620 /// Add a job to the queue of this multi-priority thread pool indicated
621 /// by the specified `jobFunction` and associated `jobData`, assigning
622 /// it the specified `priority`. Return 0 if the job was enqueued
623 /// successfully, and a non-zero value otherwise (implying that the
624 /// queue was in the disabled state). When invoked, `jobFunction` is
625 /// passed the `void *` address `jobData` as its only argument. The
626 /// behavior is undefined unless `jobFunction` is non-null and
627 /// `0 <= priority < numPriorities()`. Note that `jobData` may be 0 as
628 /// long as `jobFunction` supports that value.
630 void *jobData,
631 int priority);
632
633 /// Enable the enqueuing of jobs to this multi-priority thread pool.
634 /// When this thread pool is enabled, the status returned when calling
635 /// either overloaded `enqueueJob` method will be 0, indicating that the
636 /// job was successfully enqueued. Note that calling this method when
637 /// the queue is already in the enabled state has no effect.
639
640 /// Disable the enqueuing of jobs to this multi-priority thread pool.
641 /// When this thread pool is disabled, the status returned when calling
642 /// either overloaded `enqueueJob` method will be non-zero, indicating
643 /// that the job was *not* enqueued. Note that calling this method when
644 /// the queue is already in the disabled state has no effect.
646
647 /// Create and start `numThreads()` worker threads in this
648 /// multi-priority thread pool. Return 0 on success, and a non-zero
649 /// value with no worker threads and no jobs processed otherwise. This
650 /// method has no impact on the enabled/disabled or suspended/resumed
651 /// states of this thread pool. Note that calling this method when this
652 /// thread pool is already in the started state has no effect. Also
653 /// note that until this method is called, the thread pool will not
654 /// process any jobs.
656
657 /// Destroy all worker threads of this multi-priority thread pool after
658 /// waiting for any active (i.e., already-running) jobs to complete; no
659 /// new jobs will be allowed to become active. This method has no
660 /// impact on the enabled/disabled or suspended/resumed states of this
661 /// thread pool. Note that calling this function when this thread pool
662 /// is not in the started state has no effect. Also note that calling
663 /// this method from one of the threads belonging to this thread pool
664 /// will cause a deadlock.
666
667 /// Put this multi-priority thread pool into the suspended state. This
668 /// method does not suspend any jobs that have begun to execute; such
669 /// jobs are allowed to complete. No pending jobs, however, will be
670 /// allowed to begin execution until `resumeProcessing()` is called.
671 /// This is orthogonal to start/stop, and enable/disable; no threads are
672 /// stopped. If this thread pool is started, this call blocks until all
673 /// threads have finished any jobs they were processing and have gone
674 /// into suspension. This method has no effect if this thread pool was
675 /// already in the suspended state. Note that calling this method from
676 /// one of the threads belonging to this thread pool will cause a
677 /// deadlock.
679
680 /// If this multi-priority thread pool is suspended, resume processing
681 /// of jobs. This is orthogonal to start/stop, and enable/disable; no
682 /// threads are started. Note that this method has no effect if this
683 /// thread pool is not in the suspended state.
685
686 /// Block until all executing jobs and pending jobs enqueued to this
687 /// multi-priority thread pool complete. This method does not affect
688 /// the enabled/disabled state of this thread pool. If this thread pool
689 /// is enabled and jobs are enqueued during draining, this method may
690 /// return before all enqueued jobs are executed. The behavior is
691 /// undefined if:
692 ///
693 /// * this method is called while this thread pool is stopped or
694 /// suspended, or
695 /// * this method is called concurrently with a call to the
696 /// `removeJobs` method, or
697 /// * this method is called by one of the threads belonging to this
698 /// thread pool.
699 ///
700 /// Note that, in these cases, such undefined behavior may include
701 /// deadlock.
702 void drainJobs();
703
704 /// Remove all pending (i.e., not yet active) jobs from the queue of
705 /// this multi-priority thread pool. This method does not affect the
706 /// enabled status of the queue, nor does it affect the started status
707 /// or any active jobs in this thread pool. The behavior is undefined
708 /// if this method is called concurrently with the `drainJobs` method.
709 /// Note that, in this case, such undefined behavior may include
710 /// deadlock.
712
713 /// Disable the enqueuing of new jobs to this multi-priority thread
714 /// pool, cancel all pending jobs, and stop all worker threads.
715 void shutdown();
716
717 // ACCESSORS
718
719 /// Return `true` if the enqueuing of new jobs is enabled for this
720 /// multi-priority thread pool, and `false` otherwise.
721 bool isEnabled() const;
722
723 /// Return `true` if all `numThreads()` worker threads (specified at
724 /// construction) have been created for this multi-priority thread pool,
725 /// and `false` otherwise.
726 bool isStarted() const;
727
728 /// Return `true` if the threads of this multi-priority thread pool are
729 /// currently suspended from processing jobs, and `false` otherwise.
730 bool isSuspended() const;
731
732 /// Return a snapshot of the number of threads that are actively
733 /// processing jobs for this multi-priority thread pool. Note that
734 /// `0 <= numActiveThreads() <= numThreads()` is an invariant of this
735 /// class.
736 int numActiveThreads() const;
737
738 /// Return a snapshot of the number of jobs currently enqueued to be
739 /// processed by this multi-priority thread pool, but are not yet
740 /// running.
741 int numPendingJobs() const;
742
743 /// Return the fixed number of priorities, specified at construction,
744 /// that this multi-priority thread pool supports.
745 int numPriorities() const;
746
747 /// Return the number of threads that have been started for this
748 /// multi-priority thread pool. Note that they may be currently
749 /// suspended.
750 int numStartedThreads() const;
751
752 /// Returns the fixed number of threads, specified at construction, that
753 /// are started by this multi-priority thread pool.
754 int numThreads() const;
755};
756
757} // close package namespace
758
759
760#endif
761
762// ----------------------------------------------------------------------------
763// Copyright 2015 Bloomberg Finance L.P.
764//
765// Licensed under the Apache License, Version 2.0 (the "License");
766// you may not use this file except in compliance with the License.
767// You may obtain a copy of the License at
768//
769// http://www.apache.org/licenses/LICENSE-2.0
770//
771// Unless required by applicable law or agreed to in writing, software
772// distributed under the License is distributed on an "AS IS" BASIS,
773// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
774// See the License for the specific language governing permissions and
775// limitations under the License.
776// ----------------------------- END-OF-FILE ----------------------------------
777
778/** @} */
779/** @} */
780/** @} */
Definition bdlcc_multipriorityqueue.h:566
Definition bdlmt_multiprioritythreadpool.h:479
MultipriorityThreadPool(int numThreads, int numPriorities, const bslmt::ThreadAttributes &threadAttributes, bslma::Allocator *basicAllocator=0)
@ MAX_NUM_PRIORITIES
Definition bdlmt_multiprioritythreadpool.h:494
@ BCEP_MAX_NUM_PRIORITIES
Definition bdlmt_multiprioritythreadpool.h:493
@ k_MAX_NUM_PRIORITIES
Definition bdlmt_multiprioritythreadpool.h:491
bsl::function< void()> ThreadFunctor
Definition bdlmt_multiprioritythreadpool.h:488
MultipriorityThreadPool(int numThreads, int numPriorities, bslma::Allocator *basicAllocator=0)
int enqueueJob(const ThreadFunctor &job, int priority)
int enqueueJob(bslmt_ThreadFunction jobFunction, void *jobData, int priority)
BSLMF_NESTED_TRAIT_DECLARATION(MultipriorityThreadPool, bslma::UsesBslmaAllocator)
Forward declaration.
Definition bslstl_function.h:934
Definition bslma_allocator.h:457
Definition bslmt_condition.h:220
Definition bslmt_mutex.h:315
Definition bslmt_threadattributes.h:356
Definition bslmt_threadgroup.h:156
Definition bsls_atomic.h:743
void *(* bslmt_ThreadFunction)(void *)
Definition bslmt_threadutil.h:355
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlmt_eventscheduler.h:522
Definition bslma_usesbslmaallocator.h:343