BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlcc_queue.h
Go to the documentation of this file.
1/// @file bdlcc_queue.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlcc_queue.h -*-C++-*-
8#ifndef INCLUDED_BDLCC_QUEUE
9#define INCLUDED_BDLCC_QUEUE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlcc_queue bdlcc_queue
15/// @brief <span style="color: var(--deprecated-color-dark)">DEPRECATED:</span> Provide a thread-enabled queue of items of parameterized `TYPE`.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlcc
19/// @{
20/// @addtogroup bdlcc_queue
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlcc_queue-purpose"> Purpose</a>
25/// * <a href="#bdlcc_queue-classes"> Classes </a>
26/// * <a href="#bdlcc_queue-description"> Description </a>
27/// * <a href="#bdlcc_queue-thread-enabled-idioms-in-the-bdlcc-queue-interface"> Thread-Enabled Idioms in the bdlcc::Queue Interface </a>
28/// * <a href="#bdlcc_queue-use-of-the-bdlc-queue-interface"> Use of the bdlc::Queue Interface </a>
29/// * <a href="#bdlcc_queue-warning-synchronization-required-on-destruction"> WARNING: Synchronization Required on Destruction </a>
30/// * <a href="#bdlcc_queue-usage"> Usage </a>
31/// * <a href="#bdlcc_queue-example-1-simple-thread-pool"> Example 1: Simple Thread Pool </a>
32/// * <a href="#bdlcc_queue-example-2-multi-threaded-observer"> Example 2: Multi-Threaded Observer </a>
33///
34/// # Purpose {#bdlcc_queue-purpose}
35/// Provide a thread-enabled queue of items of parameterized `TYPE`.
36///
37/// # Classes {#bdlcc_queue-classes}
38///
39/// - bdlcc::Queue: thread-enabled `bdlc::Queue` wrapper
40///
41/// @see bdlc_queue
42///
43/// @deprecated use `bdlcc::Deque` instead.
44///
45/// # Description {#bdlcc_queue-description}
46/// This component provides a thread-enabled implementation of an
47/// efficient, in-place, indexable, double-ended queue of parameterized `TYPE`
48/// values, namely the `bdlcc::Queue<TYPE>` container. `bdlcc::Queue` is
49/// effectively a thread-enabled handle for `bdlc::Queue`, whose interface is
50/// also made available through `bdlcc::Queue`.
51///
52/// ## Thread-Enabled Idioms in the bdlcc::Queue Interface {#bdlcc_queue-thread-enabled-idioms-in-the-bdlcc-queue-interface}
53///
54///
55/// The thread-enabled `bdlcc::Queue` is similar to `bdlc::Queue` in many
56/// regards, but there are several differences in method behavior and signature
57/// that arise due to the thread-enabled nature of the queue and its anticipated
58/// usage pattern. Most notably, the `popFront` and `popBack` methods return a
59/// `TYPE` object *by* *value*, rather than returning `void`, as `bdlc::Queue`
60/// does. Moreover, if a queue object is empty, `popFront` and `popBack` will
61/// block indefinitely until an item is added to the queue.
62///
63/// As a corollary to this behavior choice, `bdlcc::Queue` also provides
64/// `timedPopFront` and `timedPopBack` methods. These methods wait until a
65/// specified timeout expires if the queue is empty, returning an item if one
66/// becomes available before the specified timeout; otherwise, they return a
67/// non-zero value to indicate that the specified timeout expired before an item
68/// was available. Note that *all* timeouts are expressed as values of type
69/// `bsls::TimeInterval` that represent **ABSOLUTE** times from 00:00:00 UTC,
70/// January 1, 1970.
71///
72/// The behavior of the `push` methods differs in a similar manner.
73/// `bdlcc::Queue` supports the notion of a suggested maximum queue size, called
74/// the "high-water mark", a value supplied at construction. The `pushFront`
75/// and `pushBack` methods will block indefinitely if the queue contains (at
76/// least) the high-water mark number of items, until the number of items falls
77/// below the high-water mark. The `timedPushFront` and `timedPushBack` are
78/// provided to limit the duration of blocking; note, however, that these
79/// methods can fail to add an item to the queue. For this reason,
80/// `bdlcc::Queue` also provides a `forcePushFront` method that will override
81/// the high-water mark, if needed, in order to succeed without blocking. Note
82/// that this design decision makes the high-water mark concept a suggestion and
83/// not an invariant.
84///
85/// ## Use of the bdlc::Queue Interface {#bdlcc_queue-use-of-the-bdlc-queue-interface}
86///
87///
88/// Class `bdlcc::Queue` provides access to an underlying `bdlc::Queue`, so
89/// clients of `bdlcc::Queue` have full access to the interface behavior of
90/// `bdlc::Queue` to inspect and modify the `bdlcc::Queue`.
91///
92/// Member function `bdlcc::Queue::queue()` provides *direct* modifiable access
93/// to the `bdlc::Queue` object used in the implementation. Member functions
94/// `bdlcc::Queue::mutex()`, `bdlcc::Queue::notEmptyCondition()`, and
95/// `bdlcc::Queue::notFullCondition()` correspondingly provide *direct*
96/// modifiable access to the underlying `bslmt::Mutex` and `bslmt::Condition`
97/// objects respectively. These underlying objects are used within
98/// `bdlcc::Queue` to manage concurrent access to the queue. Clients may use
99/// these member variables together if needed.
100///
101/// Whenever accessing the `bdlcc` queue directly, clients must be sure to lock
102/// and unlock the mutex or to signal or broadcast on the condition variable as
103/// appropriate. For example, a client might use the underlying queue and mutex
104/// as follows:
105/// @code
106/// bdlcc::Queue<myData> myWorkQueue;
107/// bdlc::Queue<myData>& rawQueue = myWorkQueue.queue();
108/// bslmt::Mutex& queueMutex = myWorkQueue.mutex();
109/// // other code omitted...
110///
111/// myData data1;
112/// myData data2;
113/// bool pairFoundFlag = 0;
114/// // Take two items from the queue atomically, if available.
115///
116/// queueMutex.lock();
117/// if (rawQueue.length() >= 2) {
118/// data1 = rawQueue.front();
119/// rawQueue.popFront();
120/// data2 = rawQueue.front();
121/// rawQueue.popFront();
122/// pairFound = 1;
123/// }
124/// queueMutex.unlock();
125///
126/// if (pairFoundFlag) {
127/// // Process the pair
128/// }
129/// @endcode
130/// Note that a future version of this component will provide access to a
131/// thread-safe "smart pointer" that will manage the `bdlc::Queue` with respect
132/// to locking and signaling. At that time, direct access to the `bdlc::Queue`
133/// will be deprecated. In the meanwhile, the user should be careful to use the
134/// `bdlc::Queue` and the synchronization objects properly.
135///
136/// ## WARNING: Synchronization Required on Destruction {#bdlcc_queue-warning-synchronization-required-on-destruction}
137///
138///
139/// The behavior for the destructor is undefined unless all access or
140/// modification of the object is completed prior to its destruction. Some form
141/// of synchronization, external to the component, is required to ensure the
142/// precondition on the destructor is met. For example, if two (or more)
143/// threads are manipulating a queue, it is *not* safe to anticipate the number
144/// of elements added to the queue, and destroy that queue immediately after the
145/// last element is popped (without additional synchronization) because one of
146/// the corresponding push functions may not have completed (push may, for
147/// instance, signal waiting threads after the element is considered added to
148/// the queue).
149///
150/// ## Usage {#bdlcc_queue-usage}
151///
152///
153/// This section illustrates intended use of this component.
154///
155/// ### Example 1: Simple Thread Pool {#bdlcc_queue-example-1-simple-thread-pool}
156///
157///
158/// The following example demonstrates a typical usage of a `bdlcc::Queue`.
159///
160/// This `bdlcc::Queue` is used to communicate between a single "producer"
161/// thread and multiple "consumer" threads. The "producer" will push work
162/// requests onto the queue, and each "consumer" will iteratively take a work
163/// request from the queue and service the request. This example shows a
164/// partial, simplified implementation of the `bdlmt::ThreadPool` class. See
165/// component @ref bdlmt_threadpool for more information.
166///
167/// We begin our example with some utility classes that define a simple "work
168/// item":
169/// @code
170/// enum {
171/// k_MAX_CONSUMER_THREADS = 10
172/// };
173///
174/// struct my_WorkData {
175/// // Work data...
176/// };
177///
178/// struct my_WorkRequest {
179/// enum RequestType {
180/// e_WORK = 1,
181/// e_STOP = 2
182/// };
183///
184/// RequestType d_type;
185/// my_WorkData d_data;
186/// // Work data...
187/// };
188/// @endcode
189/// Next, we provide a simple function to service an individual work item. The
190/// details are unimportant for this example.
191/// @code
192/// void myDoWork(my_WorkData& data)
193/// {
194/// // do some stuff...
195/// (void)data;
196/// }
197/// @endcode
198/// The `myConsumer` function will pop items off the queue and process them. As
199/// discussed above, note that the call to `queue->popFront()` will block until
200/// there is an item available on the queue. This function will be executed in
201/// multiple threads, so that each thread waits in `queue->popFront()`, and
202/// `bdlcc::Queue` guarantees that each thread gets a unique item from the
203/// queue.
204/// @code
205/// void myConsumer(bdlcc::Queue<my_WorkRequest> *queue)
206/// {
207/// while (1) {
208/// // 'popFront()' will wait for a 'my_WorkRequest' until available.
209///
210/// my_WorkRequest item = queue->popFront();
211/// if (item.d_type == my_WorkRequest::e_STOP) break;
212/// myDoWork(item.d_data);
213/// }
214/// }
215/// @endcode
216/// The function below is a callback for `bslmt::ThreadUtil`, which requires a
217/// "C" signature. `bslmt::ThreadUtil::create()` expects a pointer to this
218/// function, and provides that function pointer to the newly created thread.
219/// The new thread then executes this function.
220///
221/// Since `bslmt::ThreadUtil::create()` uses the familiar "C" convention of
222/// passing a `void` pointer, our function simply casts that pointer to our
223/// required type (`bdlcc::Queue<my_WorkRequest*> *`), and then delegates to the
224/// queue-specific function `myConsumer`, above.
225/// @code
226/// extern "C" void *myConsumerThread(void *queuePtr)
227/// {
228/// myConsumer ((bdlcc::Queue<my_WorkRequest> *)queuePtr);
229/// return queuePtr;
230/// }
231/// @endcode
232/// In this simple example, the `myProducer` function serves multiple roles: it
233/// creates the `bdlcc::Queue`, starts out the consumer threads, and then
234/// produces and queues work items. When work requests are exhausted, this
235/// function queues one `STOP` item for each consumer queue.
236///
237/// When each Consumer thread reads a `STOP`, it terminates its thread-handling
238/// function. Note that, although the producer cannot control which thread
239/// `pop`s a particular work item, it can rely on the knowledge that each
240/// Consumer thread will read a single `STOP` item and then terminate.
241///
242/// Finally, the `myProducer` function "joins" each Consumer thread, which
243/// ensures that the thread itself will terminate correctly; see the
244/// @ref bslmt_threadutil component for details.
245/// @code
246/// void myProducer(int numThreads)
247/// {
248/// my_WorkRequest item;
249/// my_WorkData workData;
250///
251/// bdlcc::Queue<my_WorkRequest> queue;
252///
253/// assert(0 < numThreads && numThreads <= k_MAX_CONSUMER_THREADS);
254/// bslmt::ThreadUtil::Handle consumerHandles[k_MAX_CONSUMER_THREADS];
255///
256/// for (int i = 0; i < numThreads; ++i) {
257/// bslmt::ThreadUtil::create(&consumerHandles[i],
258/// myConsumerThread,
259/// &queue);
260/// }
261///
262/// while (!getWorkData(&workData)) {
263/// item.d_type = my_WorkRequest::e_WORK;
264/// item.d_data = workData;
265/// queue.pushBack(item);
266/// }
267///
268/// for (int i = 0; i < numThreads; ++i) {
269/// item.d_type = my_WorkRequest::e_STOP;
270/// queue.pushBack(item);
271/// }
272///
273/// for (int i = 0; i < numThreads; ++i) {
274/// bslmt::ThreadUtil::join(consumerHandles[i]);
275/// }
276/// }
277/// @endcode
278///
279/// ### Example 2: Multi-Threaded Observer {#bdlcc_queue-example-2-multi-threaded-observer}
280///
281///
282/// The previous example shows a simple mechanism for distributing work requests
283/// over multiple threads. This approach works well for large tasks that can be
284/// decomposed into discrete, independent tasks that can benefit from parallel
285/// execution. Note also that the various threads are synchronized only at the
286/// end of execution, when the Producer "joins" the various consumer threads.
287///
288/// The simple strategy used in the first example works well for tasks that
289/// share no state, and are completely independent of one another. For
290/// instance, a web server might use a similar strategy to distribute http
291/// requests across multiple worker threads.
292///
293/// In more complicated examples, it is often necessary or desirable to
294/// synchronize the separate tasks during execution. The second example below
295/// shows a single "Observer" mechanism that receives event notification from
296/// the various worker threads.
297///
298/// We first create a simple `my_Event` data type. Worker threads will use this
299/// data type to report information about their work. In our example, we will
300/// report the "worker Id", the event number, and some arbitrary text.
301///
302/// As with the previous example, class `my_Event` also contains an `EventType`,
303/// which is an enumeration which that indicates whether the worker has
304/// completed all work. The "Observer" will use this enumerated value to note
305/// when a Worker thread has completed its work.
306/// @code
307/// enum {
308/// k_MAX_CONSUMER_THREADS = 10,
309/// k_MAX_EVENT_TEXT = 80
310/// };
311///
312/// struct my_Event {
313/// enum EventType {
314/// e_IN_PROGRESS = 1,
315/// e_TASK_COMPLETE = 2
316/// };
317///
318/// EventType d_type;
319/// int d_workerId;
320/// int d_eventNumber;
321/// char d_eventText[k_MAX_EVENT_TEXT];
322/// };
323/// @endcode
324/// As noted in the previous example, `bslmt::ThreadUtil::create()` spawns a new
325/// thread, which invokes a simple "C" function taking a `void` pointer. In the
326/// previous example, we simply converted that `void` pointer into a pointer to
327/// the parameterized `bdlcc::Queue<TYPE>` object.
328///
329/// In this example, we want to pass an additional data item. Each worker
330/// thread is initialized with a unique integer value ("worker Id") that
331/// identifies that thread. We create a simple data structure that contains
332/// both of these values:
333/// @code
334/// struct my_WorkerData {
335/// int d_workerId;
336/// bdlcc::Queue<my_Event> *d_queue_p;
337/// };
338/// @endcode
339/// Function `myWorker` simulates a working thread by enqueuing multiple
340/// `my_Event` events during execution. In a normal application, each
341/// `my_Event` structure would likely contain different textual information; for
342/// the sake of simplicity, our loop uses a constant value for the text field.
343/// @code
344/// void myWorker(int workerId, bdlcc::Queue<my_Event> *queue)
345/// {
346/// const int NEVENTS = 5;
347/// int evnum;
348///
349/// for (evnum = 0; evnum < NEVENTS; ++evnum) {
350/// my_Event ev = {
351/// my_Event::e_IN_PROGRESS,
352/// workerId,
353/// evnum,
354/// "In-Progress Event"
355/// };
356/// queue->pushBack(ev);
357/// }
358///
359/// my_Event ev = {
360/// my_Event::e_TASK_COMPLETE,
361/// workerId,
362/// evnum,
363/// "Task Complete"
364/// };
365/// queue->pushBack(ev);
366/// }
367/// @endcode
368/// The callback function invoked by `bslmt::ThreadUtil::create()` takes the
369/// traditional `void` pointer. The expected data is the composite structure
370/// `my_WorkerData`. The callback function casts the `void` pointer to the
371/// application-specific data type and then uses the referenced object to
372/// construct a call to the `myWorker` function.
373/// @code
374/// extern "C" void *myWorkerThread(void *v_worker_p)
375/// {
376/// my_WorkerData *worker_p = (my_WorkerData *) v_worker_p;
377/// myWorker(worker_p->d_workerId, worker_p->d_queue_p);
378/// return v_worker_p;
379/// }
380/// @endcode
381/// For the sake of simplicity, we will implement the Observer behavior in the
382/// main thread. The `void` function `myObserver` starts out multiple threads
383/// running the `myWorker` function, reads `my_Event`s from the queue, and logs
384/// all messages in the order of arrival.
385///
386/// As each `myWorker` thread terminates, it sends a `e_TASK_COMPLETE` event.
387/// Upon receiving this event, the `myObserver` function uses the `d_workerId`
388/// to find the relevant thread, and then "joins" that thread.
389///
390/// The `myObserver` function determines when all tasks have completed simply by
391/// counting the number of `e_TASK_COMPLETE` messages received.
392/// @code
393/// void myObserver()
394/// {
395/// const int NTHREADS = 10;
396/// bdlcc::Queue<my_Event> queue;
397///
398/// assert(NTHREADS > 0 && NTHREADS <= k_MAX_CONSUMER_THREADS);
399/// bslmt::ThreadUtil::Handle workerHandles[k_MAX_CONSUMER_THREADS];
400///
401/// my_WorkerData workerData;
402/// workerData.d_queue_p = &queue;
403/// for (int i = 0; i < NTHREADS; ++i) {
404/// workerData.d_workerId = i;
405/// bslmt::ThreadUtil::create(&workerHandles[i],
406/// myWorkerThread,
407/// &workerData);
408/// }
409/// int nStop = 0;
410/// while (nStop < NTHREADS) {
411/// my_Event ev = queue.popFront();
412/// bsl::cout << "[" << ev.d_workerId << "] "
413/// << ev.d_eventNumber << ". "
414/// << ev.d_eventText << bsl::endl;
415/// if (my_Event::e_TASK_COMPLETE == ev.d_type) {
416/// ++nStop;
417/// bslmt::ThreadUtil::join(workerHandles[ev.d_workerId]);
418/// }
419/// }
420/// }
421/// @endcode
422/// @}
423/** @} */
424/** @} */
425
426/** @addtogroup bdl
427 * @{
428 */
429/** @addtogroup bdlcc
430 * @{
431 */
432/** @addtogroup bdlcc_queue
433 * @{
434 */
435
436#include <bdlscm_version.h>
437
438#include <bdlc_queue.h>
439
440#include <bslma_allocator.h>
442
444
445#include <bslmt_condition.h>
446#include <bslmt_lockguard.h>
447#include <bslmt_mutex.h>
448#include <bslmt_threadutil.h>
449
450#include <bslmf_movableref.h>
451
452#include <bsls_libraryfeatures.h>
453#include <bsls_timeinterval.h>
454
455#include <bsl_vector.h>
456
457#include <vector>
458
459
460namespace bdlcc {
461
462 // ===========
463 // class Queue
464 // ===========
465
466/// This class provides a thread-enabled implementation of an efficient,
467/// in-place, indexable, double-ended queue of parameterized `TYPE` values.
468/// Very efficient access to the underlying `bdlc::Queue` object is provided,
469/// as well as to a `bslmt::Mutex` and a `bslmt::Condition` variable, to facilitate thread-safe use of the `bdlc::Queue`.
470///
471/// \note Note that `Queue` is not
472/// a value-semantic type, but the underlying `bdlc::Queue` is. In this
473/// regard, `Queue` is a thread-enabled handle for a `bdlc::Queue`.
474///
475/// See @ref bdlcc_queue
476template <class TYPE>
477class Queue {
478
479 // PRIVATE TYPES
481 // We need this typedef to work
482 // around a bug in Sun WorkShop 6
483 // update 1: if the typedef is
484 // replaced by its actual definition
485 // in the two constructors
486 // initialization list, the compiler
487 // erroneously reports a syntax
488 // error ("Expected an expression").
489
490 template <class VECTOR>
491 struct IsVector;
492
493 // DATA
494 mutable
495 bslmt::Mutex d_mutex; // mutex object used to synchronize
496 // access to this queue
497
498 bslmt::Condition d_notEmptyCondition; // condition variable used to signal
499 // that new data is available in the
500 // queue
501
502 bslmt::Condition d_notFullCondition; // condition variable used to signal
503 // when there is room available to
504 // add new data to the queue
505
506 bdlc::Queue<TYPE> d_queue; // the queue, with allocator as last
507 // data member
508
509 const int d_highWaterMark; // positive maximum number of items
510 // that can be queued before
511 // insertions will be blocked, or
512 // -1 if unlimited
513
514 private:
515 // NOT IMPLEMENTED
516 Queue(const Queue<TYPE>&);
517 Queue<TYPE>& operator=(const Queue<TYPE>&);
518
519 // PRIVATE MANIPULATORS
520
521 /// Remove all the items in this queue. If the optionally specified
522 /// `buffer` is not 0, load into `buffer` a copy of the items removed in
523 /// front to back order of the queue prior to `removeAll`.
524 template <class VECTOR>
525 void removeAllImp(VECTOR *buffer = 0);
526
527 /// Remove up to the specified `maxNumItems` from the front of this
528 /// queue. Optionally specify a `buffer` into which the items removed
529 /// from the queue are loaded. If `buffer` is non-null, the removed
530 /// items are appended to it as if by repeated application of
531 /// `buffer->push_back(popFront())` while the queue is not empty and
532 /// `maxNumItems` have not yet been removed.
533 ///
534 /// \pre The behavior is undefined unless `maxNumItems >= 0`. This method never blocks.
535 template <class VECTOR>
536 void tryPopFrontImp(int maxNumItems, VECTOR *buffer);
537
538 /// Remove up to the specified `maxNumItems` from the back of this
539 /// queue. Optionally specify a `buffer` into which the items removed
540 /// from the queue are loaded. If `buffer` is non-null, the removed
541 /// items are appended to it as if by repeated application of
542 /// `buffer->push_back(popBack())` while the queue is not empty and
543 /// `maxNumItems` have not yet been removed. This method never blocks.
544 ///
545 /// \pre The behavior is undefined unless `maxNumItems >= 0`.
546 /// \note Note that the
547 /// ordering of the items in `*buffer` after the call is the reverse of
548 /// the ordering they had in the queue.
549 template <class VECTOR>
550 void tryPopBackImp(int maxNumItems, VECTOR *buffer);
551
552 public:
553 // TRAITS
555
556 // TYPES
557
558 /// Enable uniform use of an optional integral constructor argument to
559 /// specify the initial internal capacity (in items). For example,
560 /// @code
561 /// const Queue<int>::InitialCapacity NUM_ITEMS(8));
562 /// Queue<int> x(NUM_ITEMS);
563 /// @endcode
564 /// defines an instance `x` with an initial capacity of 8 items, but
565 /// with a logical length of 0 items.
566 ///
567 /// See @ref bdlcc_queue
569
570 // DATA
571 unsigned int d_i;
572
573 // CREATORS
574
575 /// Create an object with the specified value `i`.
576 explicit InitialCapacity(int i)
577 : d_i(i)
578 {}
579 };
580
581 // CREATORS
582
583 /// Create a queue of objects of parameterized `TYPE`. Optionally
584 /// specify a `basicAllocator` used to supply memory. If
585 /// `basicAllocator` is 0, the currently installed default allocator is
586 /// used.
587 explicit
588 Queue(bslma::Allocator *basicAllocator = 0);
589
590 /// Create a queue of objects of parameterized `TYPE` having either the
591 /// specified `highWaterMark` suggested maximum length if
592 /// `highWaterMark` is positive, or no maximum length if `highWaterMark`
593 /// is negative. Optionally specify a `basicAllocator` used to supply
594 /// memory. If `basicAllocator` is 0, the currently installed default allocator is used.
595 ///
596 /// \pre The behavior is undefined unless
597 /// `highWaterMark != 0`.
598 explicit
599 Queue(int highWaterMark, bslma::Allocator *basicAllocator = 0);
600
601 /// Create a queue of objects of parameterized `TYPE` with sufficient
602 /// initial capacity to accommodate up to the specified `numItems`
603 /// values without subsequent reallocation. Optionally specify a
604 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
605 /// the currently installed default allocator is used.
606 explicit
607 Queue(const InitialCapacity& numItems,
608 bslma::Allocator *basicAllocator = 0);
609
610 /// Create a queue of objects of parameterized `TYPE` with sufficient
611 /// initial capacity to accommodate up to the specified `numItems`
612 /// values without subsequent reallocation and having either the
613 /// specified `highWaterMark` suggested maximum length if
614 /// `highWaterMark` is positive, or no maximum length if `highWaterMark`
615 /// is negative. Optionally specify a `basicAllocator` used to supply
616 /// memory. If `basicAllocator` is 0, the currently installed default allocator is used.
617 ///
618 /// \pre The behavior is undefined unless
619 /// `highWaterMark != 0`.
620 Queue(const InitialCapacity& numItems,
621 int highWaterMark,
622 bslma::Allocator *basicAllocator = 0);
623
624 /// Create a queue of objects of parameterized `TYPE` containing the
625 /// sequence of `TYPE` values from the specified `srcQueue`. Optionally
626 /// specify a `basicAllocator` used to supply memory. If
627 /// `basicAllocator` is 0, the currently installed default allocator is
628 /// used.
629 Queue(const bdlc::Queue<TYPE>& srcQueue,
630 bslma::Allocator *basicAllocator = 0); // IMPLICIT
631
632 /// Create a queue of objects of parameterized `TYPE` containing the
633 /// sequence of `TYPE` values from the specified `srcQueue` and having
634 /// either the specified `highWaterMark` suggested maximum length if
635 /// `highWaterMark` is positive, or no maximum length if `highWaterMark`
636 /// is negative. Optionally specify a `basicAllocator` used to supply
637 /// memory. If `basicAllocator` is 0, the currently installed default allocator is used.
638 ///
639 /// \pre The behavior is undefined unless
640 /// `highWaterMark != 0`.
641 Queue(const bdlc::Queue<TYPE>& srcQueue,
642 int highWaterMark,
643 bslma::Allocator *basicAllocator = 0);
644
645 /// Destroy this container.
646 /// \pre The behavior is undefined unless all access
647 /// or modification of the container has completed prior to this call.
648 ~Queue();
649
650 // MANIPULATORS
651
652 /// Remove the last item in this queue and load that item into the
653 /// specified `buffer`. If this queue is empty, block until an item is
654 /// available.
655 void popBack(TYPE *buffer);
656
657 /// Remove the last item in this queue and return that item value. If
658 /// this queue is empty, block until an item is available.
659 TYPE popBack();
660
661 /// Remove the last item in this queue and load that item value into the
662 /// specified `buffer`. If this queue is empty, block until an item is
663 /// available or until the specified `timeout` (expressed as the
664 /// **ABSOLUTE** time from 00:00:00 UTC, January 1, 1970) expires. Return
665 /// 0 on success, and a non-zero value if the call timed out before an
666 /// item was available.
667 int timedPopBack(TYPE *buffer, const bsls::TimeInterval& timeout);
668
669 /// Remove the first item in this queue and load that item into the
670 /// specified `buffer`. If the queue is empty, block until an item is
671 /// available.
672 void popFront(TYPE *buffer);
673
674 /// Remove the first item in this queue and return that item value. If
675 /// the queue is empty, block until an item is available.
676 TYPE popFront();
677
678 /// Remove the first item in this queue and load that item value into
679 /// the specified `buffer`. If this queue is empty, block until an item
680 /// is available or until the specified `timeout` (expressed as the
681 /// **ABSOLUTE** time from 00:00:00 UTC, January 1, 1970) expires. Return
682 /// 0 on success, and a non-zero value if the call timed out before an
683 /// item was available.
684 int timedPopFront(TYPE *buffer, const bsls::TimeInterval& timeout);
685
686 /// Remove all the items in this queue. If the optionally specified
687 /// `buffer` is not 0, load into `buffer` a copy of the items removed in
688 /// front to back order of the queue prior to `removeAll`.
689 void removeAll();
690 void removeAll(bsl::vector<TYPE> *buffer);
691 void removeAll(std::vector<TYPE> *buffer);
692#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
693 void removeAll(std::pmr::vector<TYPE> *buffer);
694#endif
695
696 /// Append the specified `item` to the back of this queue. If the
697 /// high-water mark is non-negative and the number of items in this
698 /// queue is greater than or equal to the high-water mark, then block
699 /// until the number of items in this queue is less than the high-water
700 /// mark.
701 void pushBack(const TYPE& item);
702
703 /// Append the specified `item` to the front of this queue. If the
704 /// high-water mark is non-negative and the number of items in this
705 /// queue is greater than or equal to the high-water mark, then block
706 /// until the number of items in this queue is less than the high-water
707 /// mark.
708 void pushFront(const TYPE& item);
709
710 /// Append the specified `item` to the back of this queue. If the
711 /// high-water mark is non-negative and the number of items in this
712 /// queue is greater than or equal to the high-water mark, then block
713 /// until the number of items in this queue is less than the high-water
714 /// mark or until the specified `timeout` (expressed as the **ABSOLUTE**
715 /// time from 00:00:00 UTC, January 1, 1970) expires. Return 0 on
716 /// success, and a non-zero value if the call timed out before the
717 /// number of items in this queue fell below the high-water mark.
718 int timedPushBack(const TYPE& item, const bsls::TimeInterval& timeout);
719
720 /// Append the specified `item` to the front of this queue. If the high
721 /// water mark is non-negative and the number of items in this queue is
722 /// greater than or equal to the high-water mark, then block until the
723 /// number of items in this queue is less than the high-water mark or
724 /// until the specified `timeout` (expressed as the **ABSOLUTE** time from
725 /// 00:00:00 UTC, January 1, 1970) expires. Return 0 on success, and a
726 /// non-zero value if the call timed out before the number of items in
727 /// this queue fell below the high-water mark.
728 int timedPushFront(const TYPE& item, const bsls::TimeInterval& timeout);
729
730 /// Append the specified `item` to the front of this queue without regard for the high-water mark.
731 ///
732 /// \note Note that this method is provided
733 /// to allow high priority items to be inserted when the queue is full
734 /// (i.e., has a number of items greater than or equal to its high-water
735 /// mark); `pushFront` and `pushBack` should be used for general use.
736 void forcePushFront(const TYPE& item);
737
738 /// If this queue is non-empty, remove the first item, load that item
739 /// into the specified `buffer`, and return 0 indicating success. If
740 /// this queue is empty, return a non-zero value with no effect on
741 /// `buffer` or the state of this queue. This method never blocks.
742 int tryPopFront(TYPE *buffer);
743
744 // Remove up to the specified `maxNumItems` from the front of this
745 // queue. Optionally specify a `buffer` into which the items removed
746 // from the queue are loaded. If `buffer` is non-null, the removed
747 // items are appended to it as if by repeated application of
748 // `buffer->push_back(popFront())` while the queue is not empty and
749 // `maxNumItems` have not yet been removed. The behavior is undefined
750 // unless `maxNumItems >= 0`. This method never blocks.
751 void tryPopFront(int maxNumItems);
752 void tryPopFront(int maxNumItems, bsl::vector<TYPE> *buffer);
753 void tryPopFront(int maxNumItems, std::vector<TYPE> *buffer);
754#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
755 void tryPopFront(int maxNumItems, std::pmr::vector<TYPE> *buffer);
756#endif
757
758 /// If this queue is non-empty, remove the last item, load that item into
759 /// the specified `buffer`, and return 0 indicating success. If this queue
760 /// is empty, return a non-zero value with no effect on `buffer` or the
761 /// state of this queue. This method never blocks.
762 int tryPopBack(TYPE *buffer);
763
764 // Remove up to the specified `maxNumItems` from the back of this
765 // queue. Optionally specify a `buffer` into which the items removed
766 // from the queue are loaded. If `buffer` is non-null, the removed
767 // items are appended to it as if by repeated application of
768 // `buffer->push_back(popBack())` while the queue is not empty and
769 // `maxNumItems` have not yet been removed. This method never blocks.
770 // The behavior is undefined unless `maxNumItems >= 0`. Note that the
771 // ordering of the items in `*buffer` after the call is the reverse of
772 // the ordering they had in the queue.
773 void tryPopBack(int maxNumItems);
774 void tryPopBack(int maxNumItems, bsl::vector<TYPE> *buffer);
775 void tryPopBack(int maxNumItems, std::vector<TYPE> *buffer);
776#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
777 void tryPopBack(int maxNumItems, std::pmr::vector<TYPE> *buffer);
778#endif
779
780 // *** Modifiable access to the mutex, condition variable, and queue ***
781
782 /// Return a reference to the modifiable condition variable used by this
783 /// queue to signal that the queue is not empty.
784 ///
785 /// @deprecated Use @ref notEmptyCondition instead.
787
788 /// Return a reference to the modifiable condition variable used by this
789 /// queue to signal that the queue is not full (i.e., has fewer items
790 /// than its high-water mark).
791 ///
792 /// @deprecated Use @ref notFullCondition instead.
794
795 /// Return a reference to the modifiable mutex used by this queue to
796 /// synchronize access to its underlying `bdlc::Queue` object.
798
799 /// Return the condition variable used by this queue to signal that the
800 /// queue is not empty.
802
803 /// Return the condition variable used by this queue to signal that the
804 /// queue is not full (i.e., has fewer items than its high-water mark).
806
807 /// Return a reference to the modifiable underlying `bdlc::Queue` object
808 /// used by this queue. Any access to the returned queue MUST first
809 /// lock the associated mutex object (see the `mutex` method) in a
810 /// multi-threaded environment. And when items are directly added to
811 /// the queue returned by this method, the associated condition variable
812 /// (see the `condition` method) should be signaled to notify any
813 /// waiting threads of the availability of the new data.
814 ///
815 /// The (error-prone) usage of this method will be replaced by an
816 /// appropriate smart-pointer-like proctor object in the future.
817 /// Meanwhile, use this method with caution.
819
820 // ACCESSORS
821
822 /// Return the high-water mark value for this queue.
823 /// \note Note that a negative
824 /// value indicates no suggested-maximum capacity, and is not necessarily
825 /// the same negative value that was passed to the constructor.
826 int highWaterMark() const;
827
828 /// Return the number of elements in this queue.
829 /// \note Note that if other
830 /// threads are manipulating the queue, this information may be obsolete by
831 /// the time it is returned.
832 int length() const;
833};
834
835 // ======================
836 // struct Queue::IsVector
837 // ======================
838
839/// This `struct` has a `value` that evaluates to `true` if the specified
840/// `VECTOR` is a `bsl`, `std`, or `std::pmr` `vector<TYPE>`.
841template <class TYPE>
842template <class VECTOR>
843struct Queue<TYPE>::IsVector {
844
845 static const bool value =
846 bsl::is_same<bsl::vector<TYPE>, VECTOR>::value
847#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
848 || bsl::is_same<std::pmr::vector<TYPE>, VECTOR>::value
849#endif
850 || bsl::is_same<std::vector<TYPE>, VECTOR>::value;
851};
852
853// ============================================================================
854// INLINE DEFINITIONS
855// ============================================================================
856
857// PRIVATE MANIPULATORS
858template <class TYPE>
859template <class VECTOR>
860void Queue<TYPE>::removeAllImp(VECTOR *buffer)
861{
862 BSLMF_ASSERT(IsVector<VECTOR>::value);
863
864 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
865 bool wasFull = d_highWaterMark > 0 && d_queue.length() >= d_highWaterMark;
866
867 if (buffer) {
868 for (int ii = 0, len = d_queue.length(); ii < len; ++ii) {
869 buffer->push_back(bslmf::MovableRefUtil::move(d_queue[ii]));
870 }
871 }
872 d_queue.removeAll();
873
874 lock.release()->unlock();
875
876 if (wasFull) {
877 for (int i = 0; d_highWaterMark > i; ++i) {
878 d_notFullCondition.signal();
879 }
880 }
881}
882
883template <class TYPE>
884template <class VECTOR>
885void Queue<TYPE>::tryPopFrontImp(int maxNumItems, VECTOR *buffer)
886{
887 BSLMF_ASSERT(IsVector<VECTOR>::value);
888
889 int numSignal = 0;
890 {
891 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
892
893 int length = d_queue.length();
894 const bool wasFull = d_highWaterMark > 0 && length >= d_highWaterMark;
895
896 for (; d_queue.length() > 0 && maxNumItems > 0; --maxNumItems) {
897 if (buffer) {
898 buffer->push_back(
899 bslmf::MovableRefUtil::move(d_queue.front()));
900 }
901 d_queue.popFront();
902 --length;
903 }
904
905 if (wasFull && length < d_highWaterMark) {
906 numSignal = d_highWaterMark - length;
907 }
908 }
909
910 for (; 0 < numSignal; --numSignal) {
911 d_notFullCondition.signal();
912 }
913}
914
915template <class TYPE>
916template <class VECTOR>
917void Queue<TYPE>::tryPopBackImp(int maxNumItems, VECTOR *buffer)
918{
919 BSLMF_ASSERT(IsVector<VECTOR>::value);
920
921 int numSignal = 0;
922 {
923 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
924
925 int length = d_queue.length();
926 const bool wasFull = d_highWaterMark > 0 && length >= d_highWaterMark;
927
928 for (; d_queue.length() > 0 && maxNumItems > 0; --maxNumItems) {
929 if (buffer) {
930 buffer->push_back(bslmf::MovableRefUtil::move(d_queue.back()));
931 }
932 d_queue.popBack();
933 --length;
934 }
935
936 if (wasFull && length < d_highWaterMark) {
937 numSignal = d_highWaterMark - length;
938 }
939 }
940
941 for (; 0 < numSignal; --numSignal) {
942 d_notFullCondition.signal();
943 }
944}
945
946// CREATORS
947template <class TYPE>
948inline
950: d_queue(basicAllocator)
951, d_highWaterMark(-1)
952{
953}
954
955template <class TYPE>
956inline
958 bslma::Allocator *basicAllocator)
959: d_queue(QueueCapacity(numItems.d_i), basicAllocator)
960, d_highWaterMark(-1)
961{
962}
963
964template <class TYPE>
965inline
966Queue<TYPE>::Queue(int highWaterMark, bslma::Allocator *basicAllocator)
967: d_queue(basicAllocator)
968, d_highWaterMark(highWaterMark < 0 ? -1 : highWaterMark)
969{
970}
971
972template <class TYPE>
973inline
975 int highWaterMark,
976 bslma::Allocator *basicAllocator)
977: d_queue(QueueCapacity(numItems.d_i), basicAllocator)
978, d_highWaterMark(highWaterMark < 0 ? -1 : highWaterMark)
979{
980}
981
982template <class TYPE>
983inline
985 bslma::Allocator *basicAllocator)
986: d_queue(srcQueue, basicAllocator)
987, d_highWaterMark(-1)
988{
989}
990
991template <class TYPE>
992inline
994 int highWaterMark,
995 bslma::Allocator *basicAllocator)
996: d_queue(srcQueue, basicAllocator)
997, d_highWaterMark(highWaterMark < 0 ? -1 : highWaterMark)
998{
999}
1000
1001template <class TYPE>
1002inline
1006
1007// MANIPULATORS
1008template <class TYPE>
1009void Queue<TYPE>::popBack(TYPE *buffer)
1010{
1011 unsigned int length;
1012 {
1013 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1014
1015 while (0 == (length = d_queue.length())) {
1016 d_notEmptyCondition.wait(&d_mutex);
1017 }
1018 *buffer = d_queue.back();
1019 d_queue.popBack();
1020 --length;
1021 }
1022
1023 if (length < (unsigned) d_highWaterMark) {
1024 d_notFullCondition.signal();
1025 }
1026}
1027
1028template <class TYPE>
1030{
1031 // Note that this method is not implemented in terms of 'popBack(TYPE*)'
1032 // because that would require TYPE to have a default constructor.
1033
1034 unsigned int length;
1035
1036 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1037
1038 while (0 == (length = d_queue.length())) {
1039 d_notEmptyCondition.wait(&d_mutex);
1040 }
1041 TYPE back = d_queue.back();
1042 d_queue.popBack();
1043 --length;
1044
1045 lock.release()->unlock();
1046
1047 if (length < (unsigned) d_highWaterMark) {
1048 d_notFullCondition.signal();
1049 }
1050 return back;
1051}
1052
1053template <class TYPE>
1054int Queue<TYPE>::timedPopBack(TYPE *buffer, const bsls::TimeInterval& timeout)
1055{
1056 unsigned int length;
1057 {
1058 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1059
1060 while (0 == (length = d_queue.length())) {
1061 if (d_notEmptyCondition.timedWait(&d_mutex, timeout)) {
1062 return 1; // RETURN
1063 }
1064 }
1065 *buffer = d_queue.back();
1066 d_queue.popBack();
1067 --length;
1068 }
1069
1070 if (length < (unsigned) d_highWaterMark) {
1071 d_notFullCondition.signal();
1072 }
1073 return 0;
1074}
1075
1076template <class TYPE>
1077void Queue<TYPE>::popFront(TYPE *buffer)
1078{
1079 unsigned int length;
1080 {
1081 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1082
1083 while (0 == (length = d_queue.length())) {
1084 d_notEmptyCondition.wait(&d_mutex);
1085 }
1086 *buffer = d_queue.front();
1087 d_queue.popFront();
1088 --length;
1089 }
1090
1091 if (length < (unsigned) d_highWaterMark) {
1092 d_notFullCondition.signal();
1093 }
1094}
1095
1096template <class TYPE>
1098{
1099 // Note that this method is not implemented in terms of 'popFront(TYPE*)'
1100 // because that would require TYPE to have a default constructor.
1101
1102 unsigned int length;
1103
1104 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1105
1106 while (0 == (length = d_queue.length())) {
1107 d_notEmptyCondition.wait(&d_mutex);
1108 }
1109 TYPE front = d_queue.front();
1110 d_queue.popFront();
1111 --length;
1112
1113 lock.release()->unlock();
1114
1115 if (length < (unsigned) d_highWaterMark) {
1116 d_notFullCondition.signal();
1117 }
1118 return front;
1119}
1120
1121template <class TYPE>
1122int Queue<TYPE>::timedPopFront(TYPE *buffer, const bsls::TimeInterval& timeout)
1123{
1124 unsigned int length;
1125 {
1126 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1127
1128 while (0 == (length = d_queue.length())) {
1129 if (d_notEmptyCondition.timedWait(&d_mutex, timeout)) {
1130 return 1; // RETURN
1131 }
1132 }
1133 *buffer = d_queue.front();
1134 d_queue.popFront();
1135 --length;
1136 }
1137
1138 if (length < (unsigned) d_highWaterMark) {
1139 d_notFullCondition.signal();
1140 }
1141 return 0;
1142}
1143
1144template <class TYPE>
1146{
1147 unsigned int length;
1148 {
1149 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1150
1151 if (0 == (length = d_queue.length())) {
1152 return 1; // RETURN
1153 }
1154 *buffer = d_queue.front();
1155 d_queue.popFront();
1156 --length;
1157 }
1158
1159 if (length < (unsigned) d_highWaterMark) {
1160 d_notFullCondition.signal();
1161 }
1162 return 0;
1163}
1164
1165template <class TYPE>
1166inline
1167void Queue<TYPE>::tryPopFront(int maxNumItems)
1168{
1169 tryPopFrontImp(maxNumItems, static_cast<bsl::vector<TYPE> *>(0));
1170}
1171
1172template <class TYPE>
1173inline
1174void Queue<TYPE>::tryPopFront(int maxNumItems, bsl::vector<TYPE> *buffer)
1175{
1176 tryPopFrontImp(maxNumItems, buffer);
1177}
1178
1179template <class TYPE>
1180inline
1181void Queue<TYPE>::tryPopFront(int maxNumItems, std::vector<TYPE> *buffer)
1182{
1183 tryPopFrontImp(maxNumItems, buffer);
1184}
1185
1186#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1187template <class TYPE>
1188inline
1189void Queue<TYPE>::tryPopFront(int maxNumItems, std::pmr::vector<TYPE> *buffer)
1190{
1191 tryPopFrontImp(maxNumItems, buffer);
1192}
1193#endif
1194
1195template <class TYPE>
1197{
1198 unsigned int length;
1199 {
1200 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1201
1202 if (0 == (length = d_queue.length())) {
1203 return 1; // RETURN
1204 }
1205 *buffer = d_queue.back();
1206 d_queue.popBack();
1207 --length;
1208 }
1209
1210 if (length < (unsigned) d_highWaterMark) {
1211 d_notFullCondition.signal();
1212 }
1213 return 0;
1214}
1215
1216template <class TYPE>
1217inline
1218void Queue<TYPE>::tryPopBack(int maxNumItems)
1219{
1220 tryPopBackImp(maxNumItems, static_cast<bsl::vector<TYPE> *>(0));
1221}
1222
1223template <class TYPE>
1224inline
1225void Queue<TYPE>::tryPopBack(int maxNumItems, bsl::vector<TYPE> *buffer)
1226{
1227 tryPopBackImp(maxNumItems, buffer);
1228}
1229
1230template <class TYPE>
1231inline
1232void Queue<TYPE>::tryPopBack(int maxNumItems, std::vector<TYPE> *buffer)
1233{
1234 tryPopBackImp(maxNumItems, buffer);
1235}
1236
1237#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1238template <class TYPE>
1239inline
1240void Queue<TYPE>::tryPopBack(int maxNumItems, std::pmr::vector<TYPE> *buffer)
1241{
1242 tryPopBackImp(maxNumItems, buffer);
1243}
1244#endif
1245
1246template <class TYPE>
1248{
1249 removeAllImp(static_cast<bsl::vector<TYPE> *>(0));
1250}
1251
1252template <class TYPE>
1254{
1255 removeAllImp(buffer);
1256}
1257
1258template <class TYPE>
1259void Queue<TYPE>::removeAll(std::vector<TYPE> *buffer)
1260{
1261 removeAllImp(buffer);
1262}
1263
1264#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1265template <class TYPE>
1266void Queue<TYPE>::removeAll(std::pmr::vector<TYPE> *buffer)
1267{
1268 removeAllImp(buffer);
1269}
1270#endif
1271
1272template <class TYPE>
1273void Queue<TYPE>::pushBack(const TYPE& item)
1274{
1275 {
1276 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1277 if (d_highWaterMark >= 0) {
1278 while (d_queue.length() >= d_highWaterMark) {
1279 d_notFullCondition.wait(&d_mutex);
1280 }
1281 }
1282 d_queue.pushBack(item);
1283 }
1284
1285 d_notEmptyCondition.signal();
1286}
1287
1288template <class TYPE>
1289void Queue<TYPE>::pushFront(const TYPE& item)
1290{
1291 {
1292 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1293 if (d_highWaterMark >= 0) {
1294 while (d_queue.length() >= d_highWaterMark) {
1295 d_notFullCondition.wait(&d_mutex);
1296 }
1297 }
1298 d_queue.pushFront(item);
1299 }
1300
1301 d_notEmptyCondition.signal();
1302}
1303
1304template <class TYPE>
1305int Queue<TYPE>::timedPushBack(const TYPE& item,
1306 const bsls::TimeInterval& timeout)
1307{
1308 {
1309 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1310 if (d_highWaterMark >= 0) {
1311 while (d_queue.length() >= d_highWaterMark) {
1312 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
1313 return 1; // RETURN
1314 }
1315 }
1316 }
1317 d_queue.pushBack(item);
1318 }
1319
1320 d_notEmptyCondition.signal();
1321 return 0;
1322}
1323
1324template <class TYPE>
1325int Queue<TYPE>::timedPushFront(const TYPE& item,
1326 const bsls::TimeInterval& timeout)
1327{
1328 {
1329 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1330 if (d_highWaterMark >= 0) {
1331 while (d_queue.length() >= d_highWaterMark) {
1332 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
1333 return 1; // RETURN
1334 }
1335 }
1336 }
1337 d_queue.pushFront(item);
1338 }
1339
1340 d_notEmptyCondition.signal();
1341 return 0;
1342}
1343
1344template <class TYPE>
1345inline
1346void Queue<TYPE>::forcePushFront(const TYPE& item)
1347{
1348 {
1349 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1350 d_queue.pushFront(item);
1351 }
1352 d_notEmptyCondition.signal();
1353}
1354
1355// *** Modifiable access to the mutex, condition variable, and queue ***
1356
1357template <class TYPE>
1358inline
1360{
1361 return d_notEmptyCondition;
1362}
1363
1364template <class TYPE>
1365inline
1367{
1368 return d_notFullCondition;
1369}
1370
1371template <class TYPE>
1372inline
1374{
1375 return d_mutex;
1376}
1377
1378template <class TYPE>
1379inline
1381{
1382 return d_notEmptyCondition;
1383}
1384
1385template <class TYPE>
1386inline
1388{
1389 return d_notFullCondition;
1390}
1391
1392template <class TYPE>
1393inline
1395{
1396 return d_queue;
1397}
1398
1399// ACCESSORS
1400template <class TYPE>
1401inline
1403{
1404 return d_highWaterMark;
1405}
1406
1407template <class TYPE>
1408inline
1410{
1411 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1412
1413 return d_queue.length();
1414}
1415
1416} // close package namespace
1417
1418
1419#endif
1420
1421// ----------------------------------------------------------------------------
1422// Copyright 2015 Bloomberg Finance L.P.
1423//
1424// Licensed under the Apache License, Version 2.0 (the "License");
1425// you may not use this file except in compliance with the License.
1426// You may obtain a copy of the License at
1427//
1428// http://www.apache.org/licenses/LICENSE-2.0
1429//
1430// Unless required by applicable law or agreed to in writing, software
1431// distributed under the License is distributed on an "AS IS" BASIS,
1432// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1433// See the License for the specific language governing permissions and
1434// limitations under the License.
1435// ----------------------------- END-OF-FILE ----------------------------------
1436
1437/** @} */
1438/** @} */
1439/** @} */
Definition bdlc_queue.h:274
Definition bdlcc_queue.h:477
int tryPopBack(TYPE *buffer)
Definition bdlcc_queue.h:1196
bslmt::Condition & insertCondition()
Definition bdlcc_queue.h:1366
bdlc::Queue< TYPE > & queue()
Definition bdlcc_queue.h:1394
int length() const
Definition bdlcc_queue.h:1409
~Queue()
Definition bdlcc_queue.h:1003
void removeAll()
Definition bdlcc_queue.h:1247
int tryPopFront(TYPE *buffer)
Definition bdlcc_queue.h:1145
bslmt::Condition & notFullCondition()
Definition bdlcc_queue.h:1387
TYPE popFront()
Definition bdlcc_queue.h:1097
bslmt::Condition & notEmptyCondition()
Definition bdlcc_queue.h:1380
int timedPushFront(const TYPE &item, const bsls::TimeInterval &timeout)
Definition bdlcc_queue.h:1325
void pushBack(const TYPE &item)
Definition bdlcc_queue.h:1273
bslmt::Mutex & mutex()
Definition bdlcc_queue.h:1373
BSLMF_NESTED_TRAIT_DECLARATION(Queue, bslma::UsesBslmaAllocator)
void pushFront(const TYPE &item)
Definition bdlcc_queue.h:1289
int timedPopFront(TYPE *buffer, const bsls::TimeInterval &timeout)
Definition bdlcc_queue.h:1122
int highWaterMark() const
Definition bdlcc_queue.h:1402
int timedPopBack(TYPE *buffer, const bsls::TimeInterval &timeout)
Definition bdlcc_queue.h:1054
bslmt::Condition & condition()
Definition bdlcc_queue.h:1359
void forcePushFront(const TYPE &item)
Definition bdlcc_queue.h:1346
int timedPushBack(const TYPE &item, const bsls::TimeInterval &timeout)
Definition bdlcc_queue.h:1305
TYPE popBack()
Definition bdlcc_queue.h:1029
Definition bslstl_vector.h:1120
Definition bslma_allocator.h:545
Definition bslmt_condition.h:220
Definition bslmt_lockguard.h:234
T * release()
Definition bslmt_lockguard.h:506
Definition bslmt_mutex.h:317
Definition bsls_timeinterval.h:307
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:231
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlcc_boundedqueue.h:270
Definition bdlc_queue.h:298
Definition bdlcc_queue.h:568
InitialCapacity(int i)
Create an object with the specified value i.
Definition bdlcc_queue.h:576
unsigned int d_i
Definition bdlcc_queue.h:571
Definition bslmf_issame.h:146
Definition bslma_usesbslmaallocator.h:344
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067