BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlcc_singleconsumerqueue.h
Go to the documentation of this file.
1/// @file bdlcc_singleconsumerqueue.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlcc_singleconsumerqueue.h -*-C++-*-
8
9#ifndef INCLUDED_BDLCC_SINGLECONSUMERQUEUE
10#define INCLUDED_BDLCC_SINGLECONSUMERQUEUE
11
12#include <bsls_ident.h>
13BSLS_IDENT("$Id: $")
14
15/// @defgroup bdlcc_singleconsumerqueue bdlcc_singleconsumerqueue
16/// @brief Provide a thread-aware single consumer queue of values.
17/// @addtogroup bdl
18/// @{
19/// @addtogroup bdlcc
20/// @{
21/// @addtogroup bdlcc_singleconsumerqueue
22/// @{
23///
24/// <h1> Outline </h1>
25/// * <a href="#bdlcc_singleconsumerqueue-purpose"> Purpose</a>
26/// * <a href="#bdlcc_singleconsumerqueue-classes"> Classes </a>
27/// * <a href="#bdlcc_singleconsumerqueue-description"> Description </a>
28/// * <a href="#bdlcc_singleconsumerqueue-template-requirements"> Template Requirements </a>
29/// * <a href="#bdlcc_singleconsumerqueue-allocator-requirements"> Allocator Requirements </a>
30/// * <a href="#bdlcc_singleconsumerqueue-exception-safety"> Exception Safety </a>
31/// * <a href="#bdlcc_singleconsumerqueue-move-semantics-in-c-03"> Move Semantics in C++03 </a>
32/// * <a href="#bdlcc_singleconsumerqueue-usage"> Usage </a>
33/// * <a href="#bdlcc_singleconsumerqueue-example-1-a-simple-thread-pool"> Example 1: A Simple Thread Pool </a>
34///
35/// # Purpose {#bdlcc_singleconsumerqueue-purpose}
36/// Provide a thread-aware single consumer queue of values.
37///
38/// # Classes {#bdlcc_singleconsumerqueue-classes}
39///
40/// - bdlcc::SingleConsumerQueue: thread-aware single consumer queue of `TYPE`
41///
42/// # Description {#bdlcc_singleconsumerqueue-description}
43/// This component defines a type, `bdlcc::SingleConsumerQueue`,
44/// that provides an efficient, thread-aware queue of values assuming a single
45/// consumer (the use of `popFront`, `tryPopFront`, and `removeAll` is done by
46/// one thread or a group of threads using external synchronization). The
47/// behavior of the methods `popFront`, `tryPopFront`, and `removeAll` is
48/// undefined unless the use is by a single consumer. This class is ideal for
49/// synchronization and communication between threads in a producer-consumer
50/// model when there is only one consumer thread.
51///
52/// The queue provides `pushBack` and `popFront` methods for pushing data into
53/// the queue and popping data from the queue. The queue will allocate memory
54/// as necessary to accommodate `pushBack` invocations (`pushBack` will never
55/// block and is provided for consistency with other containers). When the
56/// queue is empty, the `popFront` methods block until data appears in the
57/// queue. Non-blocking methods `tryPushBack` and `tryPopFront` are also
58/// provided. The `tryPopFront` method fails immediately, returning a non-zero
59/// value, if the queue is empty.
60///
61/// The queue may be placed into a "enqueue disabled" state using the
62/// `disablePushBack` method. When disabled, `pushBack` and `tryPushBack` fail
63/// immediately and return an error code. The queue may be restored to normal
64/// operation with the `enablePushBack` method.
65///
66/// The queue may be placed into a "dequeue disabled" state using the
67/// `disablePopFront` method. When dequeue disabled, `popFront` and
68/// `tryPopFront` fail immediately and return an error code. Any threads
69/// blocked in `popFront` when the queue is dequeue disabled return from
70/// `popFront` immediately and return an error code.
71///
72/// ## Template Requirements {#bdlcc_singleconsumerqueue-template-requirements}
73///
74///
75/// `bdlcc::SingleConsumerQueue` is a template that is parameterized on the type
76/// of element contained within the queue. The supplied template argument,
77/// `TYPE`, must provide both a default constructor and a copy constructor, as
78/// well as an assignment operator. If the default constructor accepts a
79/// `bslma::Allocator *`, `TYPE` must declare the uses `bslma::Allocator` trait
80/// (see @ref bslma_usesbslmaallocator ) so that the allocator of the queue is
81/// propagated to the elements contained in the queue.
82///
83/// ## Allocator Requirements {#bdlcc_singleconsumerqueue-allocator-requirements}
84///
85///
86/// Access to the allocator supplied to the constructor is internally
87/// synchronized by this component. If allocations performed by this component
88/// must be synchronized with external allocations (performed outside of this
89/// component), that synchronization must be guaranteed by the user. Using a
90/// thread-safe allocator is the common way to satisfy this requirement.
91///
92/// ## Exception Safety {#bdlcc_singleconsumerqueue-exception-safety}
93///
94///
95/// A `bdlcc::SingleConsumerQueue` is exception neutral, and all of the methods
96/// of `bdlcc::SingleConsumerQueue` provide the basic exception safety guarantee
97/// (see @ref bsldoc_glossary ).
98///
99/// ## Move Semantics in C++03 {#bdlcc_singleconsumerqueue-move-semantics-in-c-03}
100///
101///
102/// Move-only types are supported by `bdlcc::SingleConsumerQueue` on C++11
103/// platforms only (where `BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES` is defined),
104/// and are not supported on C++03 platforms. Unfortunately, in C++03, there
105/// are user types where a `bslmf::MovableRef` will not safely degrade to a
106/// lvalue reference when a move constructor is not available (types providing a
107/// constructor template taking any type), so `bslmf::MovableRefUtil::move`
108/// cannot be used directly on a user supplied template type. See internal bug
109/// report 99039150 for more information.
110///
111/// ## Usage {#bdlcc_singleconsumerqueue-usage}
112///
113///
114/// This section illustrates intended use of this component.
115///
116/// ### Example 1: A Simple Thread Pool {#bdlcc_singleconsumerqueue-example-1-a-simple-thread-pool}
117///
118///
119/// In the following example a `bdlcc::SingleConsumerQueue` is used to
120/// communicate between multiple "producer" threads and a single "consumer"
121/// thread. The "producers" will push work requests onto the queue, and the
122/// "consumer" will iteratively take a work request from the queue and service
123/// the request.
124///
125/// First, we define a utility classes that handles a simple "work item":
126/// @code
127/// /// Work data...
128/// struct my_WorkData {
129/// };
130/// @endcode
131/// Next, we provide a simple function to service an individual work item. The
132/// details are unimportant for this example:
133/// @code
134/// void myDoWork(const my_WorkData& data)
135/// {
136/// // do some stuff...
137/// (void)data;
138/// }
139/// @endcode
140/// Then, we define a `myProducer` function that will push elements onto the
141/// queue until the queue is disabled. Note that the call to
142/// `queue->pushFront(&item)` will never block:
143/// @code
144/// void myProducer(bdlcc::SingleConsumerQueue<my_WorkData> *queue)
145/// {
146/// while (1) {
147/// my_WorkData item;
148/// if (queue->pushBack(item)) {
149/// return; // RETURN
150/// }
151/// }
152/// }
153/// @endcode
154/// Finally, we define a `myConsumer` function that serves multiple roles: it
155/// creates the `bdlcc::SingleConsumerQueue`, starts the producer threads, and
156/// then dequeues and processes work items. After completing an amount of work
157/// items, the queue is disabled for enqueueing, the producer threads are joined
158/// and the consumer uses `tryPopFront` until the queue is empty.
159/// @code
160/// void myConsumer(int numThreads)
161/// {
162/// enum {
163/// k_NUM_WORK_ITEMS = 1000
164/// };
165///
166/// bdlcc::SingleConsumerQueue<my_WorkData> queue;
167///
168/// bslmt::ThreadGroup producerThreads;
169/// producerThreads.addThreads(bdlf::BindUtil::bind(&myProducer, &queue),
170/// numThreads);
171///
172/// my_WorkData item;
173///
174/// for (int i = 0; i < k_NUM_WORK_ITEMS; ++i) {
175/// queue.popFront(&item);
176/// myDoWork(item);
177/// }
178///
179/// queue.disablePushBack();
180///
181/// producerThreads.joinAll();
182///
183/// while (0 == queue.tryPopFront(&item)) {
184/// myDoWork(item);
185/// }
186///
187/// ASSERT(queue.isEmpty());
188/// }
189/// @endcode
190/// @}
191/** @} */
192/** @} */
193
194/** @addtogroup bdl
195 * @{
196 */
197/** @addtogroup bdlcc
198 * @{
199 */
200/** @addtogroup bdlcc_singleconsumerqueue
201 * @{
202 */
203
204#include <bdlscm_version.h>
205
207
209
211
212#include <bslmf_movableref.h>
214
215#include <bslmt_condition.h>
216#include <bslmt_mutex.h>
217
219
220
221namespace bdlcc {
222
223 // =========================
224 // class SingleConsumerQueue
225 // =========================
226
227/// This class provides a thread-safe unbounded queue of values that assumes
228/// a single consumer thread.
229///
230/// See @ref bdlcc_singleconsumerqueue
231template <class TYPE>
233
234 // PRIVATE TYPES
235 typedef SingleConsumerQueueImpl<TYPE,
239
240 // DATA
241 Impl d_impl;
242
243 // NOT IMPLEMENTED
245 SingleConsumerQueue& operator=(const SingleConsumerQueue&);
246
247 public:
248 // TRAITS
251
252 // PUBLIC TYPES
253 typedef TYPE value_type; // The type for elements.
254
255 // PUBLIC CONSTANTS
256 enum {
260 };
261
262 // CREATORS
263
264 /// Create a thread-aware queue. Optionally specify a `basicAllocator`
265 /// used to supply memory. If `basicAllocator` is 0, the currently
266 /// installed default allocator is used.
267 explicit
268 SingleConsumerQueue(bslma::Allocator *basicAllocator = 0);
269
270 /// Create a thread-aware queue with, at least, the specified
271 /// `capacity`. Optionally specify a `basicAllocator` used to supply
272 /// memory. If `basicAllocator` is 0, the currently installed default
273 /// allocator is used.
274 explicit
275 SingleConsumerQueue(bsl::size_t capacity,
276 bslma::Allocator *basicAllocator = 0);
277
278 /// Destroy this object.
280
281 // MANIPULATORS
282
283 /// Remove the element from the front of this queue and load that
284 /// element into the specified `value`. If the queue is empty, block
285 /// until it is not empty. Return 0 on success, and a non-zero value
286 /// otherwise. Specifically, return `e_DISABLED` if
287 /// `isPopFrontDisabled()`. On failure, `value` is not changed.
288 /// Threads blocked due to the queue being empty will return
289 /// `e_DISABLED` if `disablePopFront` is invoked. The behavior is
290 /// undefined unless the invoker of this method is the single consumer.
291 int popFront(TYPE* value);
292
293 /// Append the specified `value` to the back of this queue. Return 0 on
294 /// success, and a non-zero value otherwise. Specifically, return
295 /// `e_DISABLED` if `isPushBackDisabled()`.
296 int pushBack(const TYPE& value);
297
298 /// Append the specified move-insertable `value` to the back of this
299 /// queue. `value` is left in a valid but unspecified state. Return 0
300 /// on success, and a non-zero value otherwise. Specifically, return
301 /// `e_DISABLED` if `isPushBackDisabled()`. On failure, `value` is not
302 /// changed.
304
305 /// Remove all items currently in this queue. Note that this operation
306 /// is not atomic; if other threads are concurrently pushing items into
307 /// the queue the result of `numElements()` after this function returns
308 /// is not guaranteed to be 0. The behavior is undefined unless the
309 /// invoker of this method is the single consumer.
310 void removeAll();
311
312 /// Attempt to remove the element from the front of this queue without
313 /// blocking, and, if successful, load the specified `value` with the
314 /// removed element. Return 0 on success, and a non-zero value
315 /// otherwise. Specifically, return `e_DISABLED` if
316 /// `isPopFrontDisabled()`, and `e_EMPTY` if `!isPopFrontDisabled()` and
317 /// the queue was empty. On failure, `value` is not changed. The
318 /// behavior is undefined unless the invoker of this method is the
319 /// single consumer.
320 int tryPopFront(TYPE *value);
321
322 /// Append the specified `value` to the back of this queue. Return 0 on
323 /// success, and a non-zero value otherwise. Specifically, return
324 /// `e_DISABLED` if `isPushBackDisabled()`.
325 int tryPushBack(const TYPE& value);
326
327 /// Append the specified move-insertable `value` to the back of this
328 /// queue. `value` is left in a valid but unspecified state. Return 0
329 /// on success, and a non-zero value otherwise. Specifically, return
330 /// `e_DISABLED` if `isPushBackDisabled()`. On failure, `value` is not
331 /// changed.
333
334 // Enqueue/Dequeue State
335
336 /// Disable dequeueing from this queue. All subsequent invocations of
337 /// `popFront` or `tryPopFront` will fail immediately. All blocked
338 /// invocations of `popFront` and `waitUntilEmpty` will fail
339 /// immediately. If the queue is already dequeue disabled, this method
340 /// has no effect.
341 void disablePopFront();
342
343 /// Disable enqueueing into this queue. All subsequent invocations of
344 /// `pushBack` or `tryPushBack` will fail immediately. All blocked
345 /// invocations of `pushBack` will fail immediately. If the queue is
346 /// already enqueue disabled, this method has no effect.
347 void disablePushBack();
348
349 /// Enable queuing. If the queue is not enqueue disabled, this call has
350 /// no effect.
351 void enablePushBack();
352
353 /// Enable dequeueing. If the queue is not dequeue disabled, this call
354 /// has no effect.
355 void enablePopFront();
356
357 // ACCESSORS
358
359 /// Return `true` if this queue is empty (has no elements), or `false`
360 /// otherwise.
361 bool isEmpty() const;
362
363 /// Return `true` if this queue is full (has no available capacity), or
364 /// `false` otherwise. Note that for unbounded queues, this method
365 /// always returns `false`.
366 bool isFull() const;
367
368 /// Return `true` if this queue is dequeue disabled, and `false`
369 /// otherwise. Note that the queue is created in the "dequeue enabled"
370 /// state.
371 bool isPopFrontDisabled() const;
372
373 /// Return `true` if this queue is enqueue disabled, and `false`
374 /// otherwise. Note that the queue is created in the "enqueue enabled"
375 /// state.
376 bool isPushBackDisabled() const;
377
378 /// Returns the number of elements currently in this queue.
379 bsl::size_t numElements() const;
380
381 /// Block until all the elements in this queue are removed. Return 0 on
382 /// success, and a non-zero value otherwise. Specifically, return
383 /// `e_DISABLED` if `!isEmpty() && isPopFrontDisabled()`. A blocked
384 /// thread waiting for the queue to empty will return `e_DISABLED` if
385 /// `disablePopFront` is invoked.
386 int waitUntilEmpty() const;
387
388 // Aspects
389
390 /// Return the allocator used by this object to supply memory.
392};
393
394// ============================================================================
395// INLINE DEFINITIONS
396// ============================================================================
397
398 // -------------------------
399 // class SingleConsumerQueue
400 // -------------------------
401
402// CREATORS
403template <class TYPE>
405 bslma::Allocator *basicAllocator)
406: d_impl(basicAllocator)
407{
408}
409
410template <class TYPE>
412 bsl::size_t capacity,
413 bslma::Allocator *basicAllocator)
414: d_impl(capacity, basicAllocator)
415{
416}
417
418// MANIPULATORS
419template <class TYPE>
421{
422 return d_impl.popFront(value);
423}
424
425template <class TYPE>
427{
428 return d_impl.pushBack(value);
429}
430
431template <class TYPE>
433{
434 return d_impl.pushBack(bslmf::MovableRefUtil::move(value));
435}
436
437template <class TYPE>
439{
440 d_impl.removeAll();
441}
442
443template <class TYPE>
445{
446 return d_impl.tryPopFront(value);
447}
448
449template <class TYPE>
451{
452 return d_impl.tryPushBack(value);
453}
454
455template <class TYPE>
457{
458 return d_impl.tryPushBack(bslmf::MovableRefUtil::move(value));
459}
460
461 // Enqueue/Dequeue State
462
463template <class TYPE>
465{
466 d_impl.disablePopFront();
467}
468
469template <class TYPE>
471{
472 d_impl.disablePushBack();
473}
474
475template <class TYPE>
477{
478 d_impl.enablePopFront();
479}
480
481template <class TYPE>
483{
484 d_impl.enablePushBack();
485}
486
487// ACCESSORS
488template <class TYPE>
490{
491 return d_impl.isEmpty();
492}
493
494template <class TYPE>
496{
497 return d_impl.isFull();
498}
499
500template <class TYPE>
502{
503 return d_impl.isPopFrontDisabled();
504}
505
506template <class TYPE>
508{
509 return d_impl.isPushBackDisabled();
510}
511
512template <class TYPE>
514{
515 return d_impl.numElements();
516}
517
518template <class TYPE>
520{
521 return d_impl.waitUntilEmpty();
522}
523
524 // Aspects
525
526template <class TYPE>
528{
529 return d_impl.allocator();
530}
531
532} // close package namespace
533
534
535#endif
536
537// ----------------------------------------------------------------------------
538// Copyright 2019 Bloomberg Finance L.P.
539//
540// Licensed under the Apache License, Version 2.0 (the "License");
541// you may not use this file except in compliance with the License.
542// You may obtain a copy of the License at
543//
544// http://www.apache.org/licenses/LICENSE-2.0
545//
546// Unless required by applicable law or agreed to in writing, software
547// distributed under the License is distributed on an "AS IS" BASIS,
548// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
549// See the License for the specific language governing permissions and
550// limitations under the License.
551// ----------------------------- END-OF-FILE ----------------------------------
552
553/** @} */
554/** @} */
555/** @} */
Definition bdlcc_singleconsumerqueueimpl.h:283
Definition bdlcc_singleconsumerqueue.h:232
bslma::Allocator * allocator() const
Return the allocator used by this object to supply memory.
Definition bdlcc_singleconsumerqueue.h:527
void enablePopFront()
Definition bdlcc_singleconsumerqueue.h:476
void disablePushBack()
Definition bdlcc_singleconsumerqueue.h:470
bool isFull() const
Definition bdlcc_singleconsumerqueue.h:495
bsl::size_t numElements() const
Returns the number of elements currently in this queue.
Definition bdlcc_singleconsumerqueue.h:513
BSLMF_NESTED_TRAIT_DECLARATION(SingleConsumerQueue, bslma::UsesBslmaAllocator)
int pushBack(const TYPE &value)
Definition bdlcc_singleconsumerqueue.h:426
int waitUntilEmpty() const
Definition bdlcc_singleconsumerqueue.h:519
~SingleConsumerQueue()=default
Destroy this object.
bool isEmpty() const
Definition bdlcc_singleconsumerqueue.h:489
void enablePushBack()
Definition bdlcc_singleconsumerqueue.h:482
TYPE value_type
Definition bdlcc_singleconsumerqueue.h:253
bool isPopFrontDisabled() const
Definition bdlcc_singleconsumerqueue.h:501
int tryPushBack(const TYPE &value)
Definition bdlcc_singleconsumerqueue.h:450
bool isPushBackDisabled() const
Definition bdlcc_singleconsumerqueue.h:507
int popFront(TYPE *value)
Definition bdlcc_singleconsumerqueue.h:420
void disablePopFront()
Definition bdlcc_singleconsumerqueue.h:464
void removeAll()
Definition bdlcc_singleconsumerqueue.h:438
int tryPopFront(TYPE *value)
Definition bdlcc_singleconsumerqueue.h:444
@ e_EMPTY
Definition bdlcc_singleconsumerqueue.h:258
@ e_SUCCESS
Definition bdlcc_singleconsumerqueue.h:257
@ e_DISABLED
Definition bdlcc_singleconsumerqueue.h:259
Definition bslma_allocator.h:457
Definition bslmf_movableref.h:751
Definition bslmt_condition.h:220
Definition bslmt_mutex.h:315
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlcc_boundedqueue.h:270
Definition bslma_usesbslmaallocator.h:343
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060
Definition bsls_atomicoperations.h:834