BDE 4.14.0 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 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
470/// facilitate thread-safe use of the `bdlc::Queue`. Note that `Queue` is not
471/// a value-semantic type, but the underlying `bdlc::Queue` is. In this
472/// regard, `Queue` is a thread-enabled handle for a `bdlc::Queue`.
473///
474/// See @ref bdlcc_queue
475template <class TYPE>
476class Queue {
477
478 // PRIVATE TYPES
480 // We need this typedef to work
481 // around a bug in Sun WorkShop 6
482 // update 1: if the typedef is
483 // replaced by its actual definition
484 // in the two constructors
485 // initialization list, the compiler
486 // erroneously reports a syntax
487 // error ("Expected an expression").
488
489 template <class VECTOR>
490 struct IsVector;
491
492 // DATA
493 mutable
494 bslmt::Mutex d_mutex; // mutex object used to synchronize
495 // access to this queue
496
497 bslmt::Condition d_notEmptyCondition; // condition variable used to signal
498 // that new data is available in the
499 // queue
500
501 bslmt::Condition d_notFullCondition; // condition variable used to signal
502 // when there is room available to
503 // add new data to the queue
504
505 bdlc::Queue<TYPE> d_queue; // the queue, with allocator as last
506 // data member
507
508 const int d_highWaterMark; // positive maximum number of items
509 // that can be queued before
510 // insertions will be blocked, or
511 // -1 if unlimited
512
513 private:
514 // NOT IMPLEMENTED
515 Queue(const Queue<TYPE>&);
516 Queue<TYPE>& operator=(const Queue<TYPE>&);
517
518 // PRIVATE MANIPULATORS
519
520 /// Remove all the items in this queue. If the optionally specified
521 /// `buffer` is not 0, load into `buffer` a copy of the items removed in
522 /// front to back order of the queue prior to `removeAll`.
523 template <class VECTOR>
524 void removeAllImp(VECTOR *buffer = 0);
525
526 /// Remove up to the specified `maxNumItems` from the front of this
527 /// queue. Optionally specify a `buffer` into which the items removed
528 /// from the queue are loaded. If `buffer` is non-null, the removed
529 /// items are appended to it as if by repeated application of
530 /// `buffer->push_back(popFront())` while the queue is not empty and
531 /// `maxNumItems` have not yet been removed. The behavior is undefined
532 /// unless `maxNumItems >= 0`. This method never blocks.
533 template <class VECTOR>
534 void tryPopFrontImp(int maxNumItems, VECTOR *buffer);
535
536 /// Remove up to the specified `maxNumItems` from the back of this
537 /// queue. Optionally specify a `buffer` into which the items removed
538 /// from the queue are loaded. If `buffer` is non-null, the removed
539 /// items are appended to it as if by repeated application of
540 /// `buffer->push_back(popBack())` while the queue is not empty and
541 /// `maxNumItems` have not yet been removed. This method never blocks.
542 /// The behavior is undefined unless `maxNumItems >= 0`. Note that the
543 /// ordering of the items in `*buffer` after the call is the reverse of
544 /// the ordering they had in the queue.
545 template <class VECTOR>
546 void tryPopBackImp(int maxNumItems, VECTOR *buffer);
547
548 public:
549 // TRAITS
551
552 // TYPES
553
554 /// Enable uniform use of an optional integral constructor argument to
555 /// specify the initial internal capacity (in items). For example,
556 /// @code
557 /// const Queue<int>::InitialCapacity NUM_ITEMS(8));
558 /// Queue<int> x(NUM_ITEMS);
559 /// @endcode
560 /// defines an instance `x` with an initial capacity of 8 items, but
561 /// with a logical length of 0 items.
563
564 // DATA
565 unsigned int d_i;
566
567 // CREATORS
568
569 /// Create an object with the specified value `i`.
570 explicit InitialCapacity(int i)
571 : d_i(i)
572 {}
573 };
574
575 // CREATORS
576
577 /// Create a queue of objects of parameterized `TYPE`. Optionally
578 /// specify a `basicAllocator` used to supply memory. If
579 /// `basicAllocator` is 0, the currently installed default allocator is
580 /// used.
581 explicit
582 Queue(bslma::Allocator *basicAllocator = 0);
583
584 /// Create a queue of objects of parameterized `TYPE` having either the
585 /// specified `highWaterMark` suggested maximum length if
586 /// `highWaterMark` is positive, or no maximum length if `highWaterMark`
587 /// is negative. Optionally specify a `basicAllocator` used to supply
588 /// memory. If `basicAllocator` is 0, the currently installed default
589 /// allocator is used. The behavior is undefined unless
590 /// `highWaterMark != 0`.
591 explicit
592 Queue(int highWaterMark, bslma::Allocator *basicAllocator = 0);
593
594 /// Create a queue of objects of parameterized `TYPE` with sufficient
595 /// initial capacity to accommodate up to the specified `numItems`
596 /// values without subsequent reallocation. Optionally specify a
597 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
598 /// the currently installed default allocator is used.
599 explicit
600 Queue(const InitialCapacity& numItems,
601 bslma::Allocator *basicAllocator = 0);
602
603 /// Create a queue of objects of parameterized `TYPE` with sufficient
604 /// initial capacity to accommodate up to the specified `numItems`
605 /// values without subsequent reallocation and having either the
606 /// specified `highWaterMark` suggested maximum length if
607 /// `highWaterMark` is positive, or no maximum length if `highWaterMark`
608 /// is negative. Optionally specify a `basicAllocator` used to supply
609 /// memory. If `basicAllocator` is 0, the currently installed default
610 /// allocator is used. The behavior is undefined unless
611 /// `highWaterMark != 0`.
612 Queue(const InitialCapacity& numItems,
613 int highWaterMark,
614 bslma::Allocator *basicAllocator = 0);
615
616 /// Create a queue of objects of parameterized `TYPE` containing the
617 /// sequence of `TYPE` values from the specified `srcQueue`. Optionally
618 /// specify a `basicAllocator` used to supply memory. If
619 /// `basicAllocator` is 0, the currently installed default allocator is
620 /// used.
621 Queue(const bdlc::Queue<TYPE>& srcQueue,
622 bslma::Allocator *basicAllocator = 0); // IMPLICIT
623
624 /// Create a queue of objects of parameterized `TYPE` containing the
625 /// sequence of `TYPE` values from the specified `srcQueue` and having
626 /// either the specified `highWaterMark` suggested maximum length if
627 /// `highWaterMark` is positive, or no maximum length if `highWaterMark`
628 /// is negative. Optionally specify a `basicAllocator` used to supply
629 /// memory. If `basicAllocator` is 0, the currently installed default
630 /// allocator is used. The behavior is undefined unless
631 /// `highWaterMark != 0`.
632 Queue(const bdlc::Queue<TYPE>& srcQueue,
633 int highWaterMark,
634 bslma::Allocator *basicAllocator = 0);
635
636 /// Destroy this container. The behavior is undefined unless all access
637 /// or modification of the container has completed prior to this call.
638 ~Queue();
639
640 // MANIPULATORS
641
642 /// Remove the last item in this queue and load that item into the
643 /// specified `buffer`. If this queue is empty, block until an item is
644 /// available.
645 void popBack(TYPE *buffer);
646
647 /// Remove the last item in this queue and return that item value. If
648 /// this queue is empty, block until an item is available.
649 TYPE popBack();
650
651 /// Remove the last item in this queue and load that item value into the
652 /// specified `buffer`. If this queue is empty, block until an item is
653 /// available or until the specified `timeout` (expressed as the
654 /// **ABSOLUTE** time from 00:00:00 UTC, January 1, 1970) expires. Return
655 /// 0 on success, and a non-zero value if the call timed out before an
656 /// item was available.
657 int timedPopBack(TYPE *buffer, const bsls::TimeInterval& timeout);
658
659 /// Remove the first item in this queue and load that item into the
660 /// specified `buffer`. If the queue is empty, block until an item is
661 /// available.
662 void popFront(TYPE *buffer);
663
664 /// Remove the first item in this queue and return that item value. If
665 /// the queue is empty, block until an item is available.
666 TYPE popFront();
667
668 /// Remove the first item in this queue and load that item value into
669 /// the specified `buffer`. If this queue is empty, block until an item
670 /// is available or until the specified `timeout` (expressed as the
671 /// **ABSOLUTE** time from 00:00:00 UTC, January 1, 1970) expires. Return
672 /// 0 on success, and a non-zero value if the call timed out before an
673 /// item was available.
674 int timedPopFront(TYPE *buffer, const bsls::TimeInterval& timeout);
675
676 void removeAll();
677 void removeAll(bsl::vector<TYPE> *buffer);
678 /// Remove all the items in this queue. If the optionally specified
679 /// `buffer` is not 0, load into `buffer` a copy of the items removed in
680 /// front to back order of the queue prior to `removeAll`.
681 void removeAll(std::vector<TYPE> *buffer);
682#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
683 void removeAll(std::pmr::vector<TYPE> *buffer);
684#endif
685
686 /// Append the specified `item` to the back of this queue. If the
687 /// high-water mark is non-negative and the number of items in this
688 /// queue is greater than or equal to the high-water mark, then block
689 /// until the number of items in this queue is less than the high-water
690 /// mark.
691 void pushBack(const TYPE& item);
692
693 /// Append the specified `item` to the front of this queue. If the
694 /// high-water mark is non-negative and the number of items in this
695 /// queue is greater than or equal to the high-water mark, then block
696 /// until the number of items in this queue is less than the high-water
697 /// mark.
698 void pushFront(const TYPE& item);
699
700 /// Append the specified `item` to the back of this queue. If the
701 /// high-water mark is non-negative and the number of items in this
702 /// queue is greater than or equal to the high-water mark, then block
703 /// until the number of items in this queue is less than the high-water
704 /// mark or until the specified `timeout` (expressed as the **ABSOLUTE**
705 /// time from 00:00:00 UTC, January 1, 1970) expires. Return 0 on
706 /// success, and a non-zero value if the call timed out before the
707 /// number of items in this queue fell below the high-water mark.
708 int timedPushBack(const TYPE& item, const bsls::TimeInterval& timeout);
709
710 /// Append the specified `item` to the front of this queue. If the high
711 /// water mark is non-negative and the number of items in this queue is
712 /// greater than or equal to the high-water mark, then block until the
713 /// number of items in this queue is less than the high-water mark or
714 /// until the specified `timeout` (expressed as the **ABSOLUTE** time from
715 /// 00:00:00 UTC, January 1, 1970) expires. Return 0 on success, and a
716 /// non-zero value if the call timed out before the number of items in
717 /// this queue fell below the high-water mark.
718 int timedPushFront(const TYPE& item, const bsls::TimeInterval& timeout);
719
720 /// Append the specified `item` to the front of this queue without
721 /// regard for the high-water mark. Note that this method is provided
722 /// to allow high priority items to be inserted when the queue is full
723 /// (i.e., has a number of items greater than or equal to its high-water
724 /// mark); `pushFront` and `pushBack` should be used for general use.
725 void forcePushFront(const TYPE& item);
726
727 /// If this queue is non-empty, remove the first item, load that item
728 /// into the specified `buffer`, and return 0 indicating success. If
729 /// this queue is empty, return a non-zero value with no effect on
730 /// `buffer` or the state of this queue. This method never blocks.
731 int tryPopFront(TYPE *buffer);
732
733 // Remove up to the specified `maxNumItems` from the front of this
734 // queue. Optionally specify a `buffer` into which the items removed
735 // from the queue are loaded. If `buffer` is non-null, the removed
736 // items are appended to it as if by repeated application of
737 // `buffer->push_back(popFront())` while the queue is not empty and
738 // `maxNumItems` have not yet been removed. The behavior is undefined
739 // unless `maxNumItems >= 0`. This method never blocks.
740 void tryPopFront(int maxNumItems);
741 void tryPopFront(int maxNumItems, bsl::vector<TYPE> *buffer);
742 void tryPopFront(int maxNumItems, std::vector<TYPE> *buffer);
743#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
744 void tryPopFront(int maxNumItems, std::pmr::vector<TYPE> *buffer);
745#endif
746
747 /// If this queue is non-empty, remove the last item, load that item into
748 /// the specified `buffer`, and return 0 indicating success. If this queue
749 /// is empty, return a non-zero value with no effect on `buffer` or the
750 /// state of this queue. This method never blocks.
751 int tryPopBack(TYPE *buffer);
752
753 // Remove up to the specified `maxNumItems` from the back of this
754 // queue. Optionally specify a `buffer` into which the items removed
755 // from the queue are loaded. If `buffer` is non-null, the removed
756 // items are appended to it as if by repeated application of
757 // `buffer->push_back(popBack())` while the queue is not empty and
758 // `maxNumItems` have not yet been removed. This method never blocks.
759 // The behavior is undefined unless `maxNumItems >= 0`. Note that the
760 // ordering of the items in `*buffer` after the call is the reverse of
761 // the ordering they had in the queue.
762 void tryPopBack(int maxNumItems);
763 void tryPopBack(int maxNumItems, bsl::vector<TYPE> *buffer);
764 void tryPopBack(int maxNumItems, std::vector<TYPE> *buffer);
765#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
766 void tryPopBack(int maxNumItems, std::pmr::vector<TYPE> *buffer);
767#endif
768
769 // *** Modifiable access to the mutex, condition variable, and queue ***
770
771 /// Return a reference to the modifiable condition variable used by this
772 /// queue to signal that the queue is not empty.
773 ///
774 /// @DEPRECATED Use `notEmptyCondition` instead.
776
777 /// Return a reference to the modifiable condition variable used by this
778 /// queue to signal that the queue is not full (i.e., has fewer items
779 /// than its high-water mark).
780 ///
781 /// @DEPRECATED Use `notFullCondition` instead.
783
784 /// Return a reference to the modifiable mutex used by this queue to
785 /// synchronize access to its underlying `bdlc::Queue` object.
787
788 /// Return the condition variable used by this queue to signal that the
789 /// queue is not empty.
791
792 /// Return the condition variable used by this queue to signal that the
793 /// queue is not full (i.e., has fewer items than its high-water mark).
795
796 /// Return a reference to the modifiable underlying `bdlc::Queue` object
797 /// used by this queue. Any access to the returned queue MUST first
798 /// lock the associated mutex object (see the `mutex` method) in a
799 /// multi-threaded environment. And when items are directly added to
800 /// the queue returned by this method, the associated condition variable
801 /// (see the `condition` method) should be signaled to notify any
802 /// waiting threads of the availability of the new data.
803 ///
804 /// The (error-prone) usage of this method will be replaced by an
805 /// appropriate smart-pointer-like proctor object in the future.
806 /// Meanwhile, use this method with caution.
808
809 // ACCESSORS
810
811 /// Return the high-water mark value for this queue. Note that a negative
812 /// value indicates no suggested-maximum capacity, and is not necessarily
813 /// the same negative value that was passed to the constructor.
814 int highWaterMark() const;
815
816 /// Return the number of elements in this queue. Note that if other
817 /// threads are manipulating the queue, this information may be obsolete by
818 /// the time it is returned.
819 int length() const;
820};
821
822 // ======================
823 // struct Queue::IsVector
824 // ======================
825
826/// This `struct` has a `value` that evaluates to `true` if the specified
827/// `VECTOR` is a `bsl`, `std`, or `std::pmr` `vector<TYPE>`.
828template <class TYPE>
829template <class VECTOR>
830struct Queue<TYPE>::IsVector {
831
832 static const bool value =
833 bsl::is_same<bsl::vector<TYPE>, VECTOR>::value
834#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
835 || bsl::is_same<std::pmr::vector<TYPE>, VECTOR>::value
836#endif
837 || bsl::is_same<std::vector<TYPE>, VECTOR>::value;
838};
839
840// ============================================================================
841// INLINE DEFINITIONS
842// ============================================================================
843
844// PRIVATE MANIPULATORS
845template <class TYPE>
846template <class VECTOR>
847void Queue<TYPE>::removeAllImp(VECTOR *buffer)
848{
849 BSLMF_ASSERT(IsVector<VECTOR>::value);
850
851 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
852 bool wasFull = d_highWaterMark > 0 && d_queue.length() >= d_highWaterMark;
853
854 if (buffer) {
855 for (int ii = 0, len = d_queue.length(); ii < len; ++ii) {
856 buffer->push_back(bslmf::MovableRefUtil::move(d_queue[ii]));
857 }
858 }
859 d_queue.removeAll();
860
861 lock.release()->unlock();
862
863 if (wasFull) {
864 for (int i = 0; d_highWaterMark > i; ++i) {
865 d_notFullCondition.signal();
866 }
867 }
868}
869
870template <class TYPE>
871template <class VECTOR>
872void Queue<TYPE>::tryPopFrontImp(int maxNumItems, VECTOR *buffer)
873{
874 BSLMF_ASSERT(IsVector<VECTOR>::value);
875
876 int numSignal = 0;
877 {
878 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
879
880 int length = d_queue.length();
881 const bool wasFull = d_highWaterMark > 0 && length >= d_highWaterMark;
882
883 for (; d_queue.length() > 0 && maxNumItems > 0; --maxNumItems) {
884 if (buffer) {
885 buffer->push_back(
886 bslmf::MovableRefUtil::move(d_queue.front()));
887 }
888 d_queue.popFront();
889 --length;
890 }
891
892 if (wasFull && length < d_highWaterMark) {
893 numSignal = d_highWaterMark - length;
894 }
895 }
896
897 for (; 0 < numSignal; --numSignal) {
898 d_notFullCondition.signal();
899 }
900}
901
902template <class TYPE>
903template <class VECTOR>
904void Queue<TYPE>::tryPopBackImp(int maxNumItems, VECTOR *buffer)
905{
906 BSLMF_ASSERT(IsVector<VECTOR>::value);
907
908 int numSignal = 0;
909 {
910 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
911
912 int length = d_queue.length();
913 const bool wasFull = d_highWaterMark > 0 && length >= d_highWaterMark;
914
915 for (; d_queue.length() > 0 && maxNumItems > 0; --maxNumItems) {
916 if (buffer) {
917 buffer->push_back(bslmf::MovableRefUtil::move(d_queue.back()));
918 }
919 d_queue.popBack();
920 --length;
921 }
922
923 if (wasFull && length < d_highWaterMark) {
924 numSignal = d_highWaterMark - length;
925 }
926 }
927
928 for (; 0 < numSignal; --numSignal) {
929 d_notFullCondition.signal();
930 }
931}
932
933// CREATORS
934template <class TYPE>
935inline
937: d_queue(basicAllocator)
938, d_highWaterMark(-1)
939{
940}
941
942template <class TYPE>
943inline
945 bslma::Allocator *basicAllocator)
946: d_queue(QueueCapacity(numItems.d_i), basicAllocator)
947, d_highWaterMark(-1)
948{
949}
950
951template <class TYPE>
952inline
953Queue<TYPE>::Queue(int highWaterMark, bslma::Allocator *basicAllocator)
954: d_queue(basicAllocator)
955, d_highWaterMark(highWaterMark < 0 ? -1 : highWaterMark)
956{
957}
958
959template <class TYPE>
960inline
962 int highWaterMark,
963 bslma::Allocator *basicAllocator)
964: d_queue(QueueCapacity(numItems.d_i), basicAllocator)
965, d_highWaterMark(highWaterMark < 0 ? -1 : highWaterMark)
966{
967}
968
969template <class TYPE>
970inline
972 bslma::Allocator *basicAllocator)
973: d_queue(srcQueue, basicAllocator)
974, d_highWaterMark(-1)
975{
976}
977
978template <class TYPE>
979inline
981 int highWaterMark,
982 bslma::Allocator *basicAllocator)
983: d_queue(srcQueue, basicAllocator)
984, d_highWaterMark(highWaterMark < 0 ? -1 : highWaterMark)
985{
986}
987
988template <class TYPE>
989inline
993
994// MANIPULATORS
995template <class TYPE>
996void Queue<TYPE>::popBack(TYPE *buffer)
997{
998 unsigned int length;
999 {
1000 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1001
1002 while (0 == (length = d_queue.length())) {
1003 d_notEmptyCondition.wait(&d_mutex);
1004 }
1005 *buffer = d_queue.back();
1006 d_queue.popBack();
1007 --length;
1008 }
1009
1010 if (length < (unsigned) d_highWaterMark) {
1011 d_notFullCondition.signal();
1012 }
1013}
1014
1015template <class TYPE>
1017{
1018 // Note that this method is not implemented in terms of 'popBack(TYPE*)'
1019 // because that would require TYPE to have a default constructor.
1020
1021 unsigned int length;
1022
1023 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1024
1025 while (0 == (length = d_queue.length())) {
1026 d_notEmptyCondition.wait(&d_mutex);
1027 }
1028 TYPE back = d_queue.back();
1029 d_queue.popBack();
1030 --length;
1031
1032 lock.release()->unlock();
1033
1034 if (length < (unsigned) d_highWaterMark) {
1035 d_notFullCondition.signal();
1036 }
1037 return back;
1038}
1039
1040template <class TYPE>
1041int Queue<TYPE>::timedPopBack(TYPE *buffer, const bsls::TimeInterval& timeout)
1042{
1043 unsigned int length;
1044 {
1045 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1046
1047 while (0 == (length = d_queue.length())) {
1048 if (d_notEmptyCondition.timedWait(&d_mutex, timeout)) {
1049 return 1; // RETURN
1050 }
1051 }
1052 *buffer = d_queue.back();
1053 d_queue.popBack();
1054 --length;
1055 }
1056
1057 if (length < (unsigned) d_highWaterMark) {
1058 d_notFullCondition.signal();
1059 }
1060 return 0;
1061}
1062
1063template <class TYPE>
1064void Queue<TYPE>::popFront(TYPE *buffer)
1065{
1066 unsigned int length;
1067 {
1068 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1069
1070 while (0 == (length = d_queue.length())) {
1071 d_notEmptyCondition.wait(&d_mutex);
1072 }
1073 *buffer = d_queue.front();
1074 d_queue.popFront();
1075 --length;
1076 }
1077
1078 if (length < (unsigned) d_highWaterMark) {
1079 d_notFullCondition.signal();
1080 }
1081}
1082
1083template <class TYPE>
1085{
1086 // Note that this method is not implemented in terms of 'popFront(TYPE*)'
1087 // because that would require TYPE to have a default constructor.
1088
1089 unsigned int length;
1090
1091 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1092
1093 while (0 == (length = d_queue.length())) {
1094 d_notEmptyCondition.wait(&d_mutex);
1095 }
1096 TYPE front = d_queue.front();
1097 d_queue.popFront();
1098 --length;
1099
1100 lock.release()->unlock();
1101
1102 if (length < (unsigned) d_highWaterMark) {
1103 d_notFullCondition.signal();
1104 }
1105 return front;
1106}
1107
1108template <class TYPE>
1109int Queue<TYPE>::timedPopFront(TYPE *buffer, const bsls::TimeInterval& timeout)
1110{
1111 unsigned int length;
1112 {
1113 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1114
1115 while (0 == (length = d_queue.length())) {
1116 if (d_notEmptyCondition.timedWait(&d_mutex, timeout)) {
1117 return 1; // RETURN
1118 }
1119 }
1120 *buffer = d_queue.front();
1121 d_queue.popFront();
1122 --length;
1123 }
1124
1125 if (length < (unsigned) d_highWaterMark) {
1126 d_notFullCondition.signal();
1127 }
1128 return 0;
1129}
1130
1131template <class TYPE>
1133{
1134 unsigned int length;
1135 {
1136 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1137
1138 if (0 == (length = d_queue.length())) {
1139 return 1; // RETURN
1140 }
1141 *buffer = d_queue.front();
1142 d_queue.popFront();
1143 --length;
1144 }
1145
1146 if (length < (unsigned) d_highWaterMark) {
1147 d_notFullCondition.signal();
1148 }
1149 return 0;
1150}
1151
1152template <class TYPE>
1153inline
1154void Queue<TYPE>::tryPopFront(int maxNumItems)
1155{
1156 tryPopFrontImp(maxNumItems, static_cast<bsl::vector<TYPE> *>(0));
1157}
1158
1159template <class TYPE>
1160inline
1161void Queue<TYPE>::tryPopFront(int maxNumItems, bsl::vector<TYPE> *buffer)
1162{
1163 tryPopFrontImp(maxNumItems, buffer);
1164}
1165
1166template <class TYPE>
1167inline
1168void Queue<TYPE>::tryPopFront(int maxNumItems, std::vector<TYPE> *buffer)
1169{
1170 tryPopFrontImp(maxNumItems, buffer);
1171}
1172
1173#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1174template <class TYPE>
1175inline
1176void Queue<TYPE>::tryPopFront(int maxNumItems, std::pmr::vector<TYPE> *buffer)
1177{
1178 tryPopFrontImp(maxNumItems, buffer);
1179}
1180#endif
1181
1182template <class TYPE>
1184{
1185 unsigned int length;
1186 {
1187 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1188
1189 if (0 == (length = d_queue.length())) {
1190 return 1; // RETURN
1191 }
1192 *buffer = d_queue.back();
1193 d_queue.popBack();
1194 --length;
1195 }
1196
1197 if (length < (unsigned) d_highWaterMark) {
1198 d_notFullCondition.signal();
1199 }
1200 return 0;
1201}
1202
1203template <class TYPE>
1204inline
1205void Queue<TYPE>::tryPopBack(int maxNumItems)
1206{
1207 tryPopBackImp(maxNumItems, static_cast<bsl::vector<TYPE> *>(0));
1208}
1209
1210template <class TYPE>
1211inline
1212void Queue<TYPE>::tryPopBack(int maxNumItems, bsl::vector<TYPE> *buffer)
1213{
1214 tryPopBackImp(maxNumItems, buffer);
1215}
1216
1217template <class TYPE>
1218inline
1219void Queue<TYPE>::tryPopBack(int maxNumItems, std::vector<TYPE> *buffer)
1220{
1221 tryPopBackImp(maxNumItems, buffer);
1222}
1223
1224#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1225template <class TYPE>
1226inline
1227void Queue<TYPE>::tryPopBack(int maxNumItems, std::pmr::vector<TYPE> *buffer)
1228{
1229 tryPopBackImp(maxNumItems, buffer);
1230}
1231#endif
1232
1233template <class TYPE>
1235{
1236 removeAllImp(static_cast<bsl::vector<TYPE> *>(0));
1237}
1238
1239template <class TYPE>
1241{
1242 removeAllImp(buffer);
1243}
1244
1245template <class TYPE>
1246void Queue<TYPE>::removeAll(std::vector<TYPE> *buffer)
1247{
1248 removeAllImp(buffer);
1249}
1250
1251#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
1252template <class TYPE>
1253void Queue<TYPE>::removeAll(std::pmr::vector<TYPE> *buffer)
1254{
1255 removeAllImp(buffer);
1256}
1257#endif
1258
1259template <class TYPE>
1260void Queue<TYPE>::pushBack(const TYPE& item)
1261{
1262 {
1263 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1264 if (d_highWaterMark >= 0) {
1265 while (d_queue.length() >= d_highWaterMark) {
1266 d_notFullCondition.wait(&d_mutex);
1267 }
1268 }
1269 d_queue.pushBack(item);
1270 }
1271
1272 d_notEmptyCondition.signal();
1273}
1274
1275template <class TYPE>
1276void Queue<TYPE>::pushFront(const TYPE& item)
1277{
1278 {
1279 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1280 if (d_highWaterMark >= 0) {
1281 while (d_queue.length() >= d_highWaterMark) {
1282 d_notFullCondition.wait(&d_mutex);
1283 }
1284 }
1285 d_queue.pushFront(item);
1286 }
1287
1288 d_notEmptyCondition.signal();
1289}
1290
1291template <class TYPE>
1292int Queue<TYPE>::timedPushBack(const TYPE& item,
1293 const bsls::TimeInterval& timeout)
1294{
1295 {
1296 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1297 if (d_highWaterMark >= 0) {
1298 while (d_queue.length() >= d_highWaterMark) {
1299 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
1300 return 1; // RETURN
1301 }
1302 }
1303 }
1304 d_queue.pushBack(item);
1305 }
1306
1307 d_notEmptyCondition.signal();
1308 return 0;
1309}
1310
1311template <class TYPE>
1312int Queue<TYPE>::timedPushFront(const TYPE& item,
1313 const bsls::TimeInterval& timeout)
1314{
1315 {
1316 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1317 if (d_highWaterMark >= 0) {
1318 while (d_queue.length() >= d_highWaterMark) {
1319 if (d_notFullCondition.timedWait(&d_mutex, timeout)) {
1320 return 1; // RETURN
1321 }
1322 }
1323 }
1324 d_queue.pushFront(item);
1325 }
1326
1327 d_notEmptyCondition.signal();
1328 return 0;
1329}
1330
1331template <class TYPE>
1332inline
1333void Queue<TYPE>::forcePushFront(const TYPE& item)
1334{
1335 {
1336 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1337 d_queue.pushFront(item);
1338 }
1339 d_notEmptyCondition.signal();
1340}
1341
1342// *** Modifiable access to the mutex, condition variable, and queue ***
1343
1344template <class TYPE>
1345inline
1347{
1348 return d_notEmptyCondition;
1349}
1350
1351template <class TYPE>
1352inline
1354{
1355 return d_notFullCondition;
1356}
1357
1358template <class TYPE>
1359inline
1361{
1362 return d_mutex;
1363}
1364
1365template <class TYPE>
1366inline
1368{
1369 return d_notEmptyCondition;
1370}
1371
1372template <class TYPE>
1373inline
1375{
1376 return d_notFullCondition;
1377}
1378
1379template <class TYPE>
1380inline
1382{
1383 return d_queue;
1384}
1385
1386// ACCESSORS
1387template <class TYPE>
1388inline
1390{
1391 return d_highWaterMark;
1392}
1393
1394template <class TYPE>
1395inline
1397{
1398 bslmt::LockGuard<bslmt::Mutex> lock(&d_mutex);
1399
1400 return d_queue.length();
1401}
1402
1403} // close package namespace
1404
1405
1406#endif
1407
1408// ----------------------------------------------------------------------------
1409// Copyright 2015 Bloomberg Finance L.P.
1410//
1411// Licensed under the Apache License, Version 2.0 (the "License");
1412// you may not use this file except in compliance with the License.
1413// You may obtain a copy of the License at
1414//
1415// http://www.apache.org/licenses/LICENSE-2.0
1416//
1417// Unless required by applicable law or agreed to in writing, software
1418// distributed under the License is distributed on an "AS IS" BASIS,
1419// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1420// See the License for the specific language governing permissions and
1421// limitations under the License.
1422// ----------------------------- END-OF-FILE ----------------------------------
1423
1424/** @} */
1425/** @} */
1426/** @} */
Definition bdlc_queue.h:273
Definition bdlcc_queue.h:476
int tryPopBack(TYPE *buffer)
Definition bdlcc_queue.h:1183
bslmt::Condition & insertCondition()
Definition bdlcc_queue.h:1353
bdlc::Queue< TYPE > & queue()
Definition bdlcc_queue.h:1381
int length() const
Definition bdlcc_queue.h:1396
~Queue()
Definition bdlcc_queue.h:990
void removeAll()
Definition bdlcc_queue.h:1234
int tryPopFront(TYPE *buffer)
Definition bdlcc_queue.h:1132
bslmt::Condition & notFullCondition()
Definition bdlcc_queue.h:1374
TYPE popFront()
Definition bdlcc_queue.h:1084
bslmt::Condition & notEmptyCondition()
Definition bdlcc_queue.h:1367
int timedPushFront(const TYPE &item, const bsls::TimeInterval &timeout)
Definition bdlcc_queue.h:1312
void pushBack(const TYPE &item)
Definition bdlcc_queue.h:1260
bslmt::Mutex & mutex()
Definition bdlcc_queue.h:1360
BSLMF_NESTED_TRAIT_DECLARATION(Queue, bslma::UsesBslmaAllocator)
void pushFront(const TYPE &item)
Definition bdlcc_queue.h:1276
int timedPopFront(TYPE *buffer, const bsls::TimeInterval &timeout)
Definition bdlcc_queue.h:1109
int highWaterMark() const
Definition bdlcc_queue.h:1389
int timedPopBack(TYPE *buffer, const bsls::TimeInterval &timeout)
Definition bdlcc_queue.h:1041
bslmt::Condition & condition()
Definition bdlcc_queue.h:1346
void forcePushFront(const TYPE &item)
Definition bdlcc_queue.h:1333
int timedPushBack(const TYPE &item, const bsls::TimeInterval &timeout)
Definition bdlcc_queue.h:1292
TYPE popBack()
Definition bdlcc_queue.h:1016
Definition bslstl_vector.h:1025
Definition bslma_allocator.h:457
Definition bslmt_condition.h:220
Definition bslmt_lockguard.h:234
T * release()
Definition bslmt_lockguard.h:493
Definition bslmt_mutex.h:315
Definition bsls_timeinterval.h:301
#define BSLMF_ASSERT(expr)
Definition bslmf_assert.h:229
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlcc_boundedqueue.h:270
Definition bdlc_queue.h:295
Definition bdlcc_queue.h:562
InitialCapacity(int i)
Create an object with the specified value i.
Definition bdlcc_queue.h:570
unsigned int d_i
Definition bdlcc_queue.h:565
Definition bslmf_issame.h:146
Definition bslma_usesbslmaallocator.h:343
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060