BDE 4.39.x 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 private:
244 // NOT IMPLEMENTED
246 SingleConsumerQueue& operator=(const SingleConsumerQueue&);
247
248 public:
249 // TRAITS
252
253 // PUBLIC TYPES
254 typedef TYPE value_type; // The type for elements.
255
256 // PUBLIC CONSTANTS
257 enum {
261 };
262
263 // CREATORS
264
265 /// Create a thread-aware queue. Optionally specify a `basicAllocator`
266 /// used to supply memory. If `basicAllocator` is 0, the currently
267 /// installed default allocator is used.
268 explicit
269 SingleConsumerQueue(bslma::Allocator *basicAllocator = 0);
270
271 /// Create a thread-aware queue with, at least, the specified
272 /// `capacity`. Optionally specify a `basicAllocator` used to supply
273 /// memory. If `basicAllocator` is 0, the currently installed default
274 /// allocator is used.
275 explicit
276 SingleConsumerQueue(bsl::size_t capacity,
277 bslma::Allocator *basicAllocator = 0);
278
279 /// Destroy this object.
281
282 // MANIPULATORS
283
284 /// Remove the element from the front of this queue and load that
285 /// element into the specified `value`. If the queue is empty, block
286 /// until it is not empty. Return 0 on success, and a non-zero value
287 /// otherwise. Specifically, return `e_DISABLED` if
288 /// `isPopFrontDisabled()`. On failure, `value` is not changed.
289 /// Threads blocked due to the queue being empty will return
290 /// `e_DISABLED` if `disablePopFront` is invoked.
291 ///
292 /// \pre The behavior is undefined unless the invoker of this method is the single consumer.
293 int popFront(TYPE* value);
294
295 /// Append the specified `value` to the back of this queue. Return 0 on
296 /// success, and a non-zero value otherwise. Specifically, return
297 /// `e_DISABLED` if `isPushBackDisabled()`.
298 int pushBack(const TYPE& value);
299
300 /// Append the specified move-insertable `value` to the back of this
301 /// queue. `value` is left in a valid but unspecified state. Return 0
302 /// on success, and a non-zero value otherwise. Specifically, return
303 /// `e_DISABLED` if `isPushBackDisabled()`. On failure, `value` is not
304 /// changed.
306
307 /// Remove all items currently in this queue.
308 /// \note Note that this operation
309 /// is not atomic; if other threads are concurrently pushing items into
310 /// the queue the result of `numElements()` after this function returns is not guaranteed to be 0.
311 ///
312 /// \pre The behavior is undefined unless the
313 /// invoker of this method is the single consumer.
314 void removeAll();
315
316 /// Attempt to remove the element from the front of this queue without
317 /// blocking, and, if successful, load the specified `value` with the
318 /// removed element. Return 0 on success, and a non-zero value
319 /// otherwise. Specifically, return `e_DISABLED` if
320 /// `isPopFrontDisabled()`, and `e_EMPTY` if `!isPopFrontDisabled()` and
321 /// the queue was empty. On failure, `value` is not changed.
322 ///
323 /// \pre The behavior is undefined unless the invoker of this method is the
324 /// single consumer.
325 int tryPopFront(TYPE *value);
326
327 /// Append the specified `value` to the back of this queue. Return 0 on
328 /// success, and a non-zero value otherwise. Specifically, return
329 /// `e_DISABLED` if `isPushBackDisabled()`.
330 int tryPushBack(const TYPE& value);
331
332 /// Append the specified move-insertable `value` to the back of this
333 /// queue. `value` is left in a valid but unspecified state. Return 0
334 /// on success, and a non-zero value otherwise. Specifically, return
335 /// `e_DISABLED` if `isPushBackDisabled()`. On failure, `value` is not
336 /// changed.
338
339 // Enqueue/Dequeue State
340
341 /// Disable dequeueing from this queue. All subsequent invocations of
342 /// `popFront` or `tryPopFront` will fail immediately. All blocked
343 /// invocations of `popFront` and `waitUntilEmpty` will fail
344 /// immediately. If the queue is already dequeue disabled, this method
345 /// has no effect.
346 void disablePopFront();
347
348 /// Disable enqueueing into this queue. All subsequent invocations of
349 /// `pushBack` or `tryPushBack` will fail immediately. All blocked
350 /// invocations of `pushBack` will fail immediately. If the queue is
351 /// already enqueue disabled, this method has no effect.
352 void disablePushBack();
353
354 /// Enable queuing. If the queue is not enqueue disabled, this call has
355 /// no effect.
356 void enablePushBack();
357
358 /// Enable dequeueing. If the queue is not dequeue disabled, this call
359 /// has no effect.
360 void enablePopFront();
361
362 // ACCESSORS
363
364 /// Return `true` if this queue is empty (has no elements), or `false`
365 /// otherwise.
366 bool isEmpty() const;
367
368 /// Return `true` if this queue is full (has no available capacity), or `false` otherwise.
369 ///
370 /// \note Note that for unbounded queues, this method
371 /// always returns `false`.
372 bool isFull() const;
373
374 /// Return `true` if this queue is dequeue disabled, and `false` otherwise.
375 ///
376 /// \note Note that the queue is created in the "dequeue enabled"
377 /// state.
378 bool isPopFrontDisabled() const;
379
380 /// Return `true` if this queue is enqueue disabled, and `false` otherwise.
381 ///
382 /// \note Note that the queue is created in the "enqueue enabled"
383 /// state.
384 bool isPushBackDisabled() const;
385
386 /// Returns the number of elements currently in this queue.
387 bsl::size_t numElements() const;
388
389 /// Block until all the elements in this queue are removed. Return 0 on
390 /// success, and a non-zero value otherwise. Specifically, return
391 /// `e_DISABLED` if `!isEmpty() && isPopFrontDisabled()`. A blocked
392 /// thread waiting for the queue to empty will return `e_DISABLED` if
393 /// `disablePopFront` is invoked.
394 int waitUntilEmpty() const;
395
396 // Aspects
397
398 /// Return the allocator used by this object to supply memory.
400};
401
402// ============================================================================
403// INLINE DEFINITIONS
404// ============================================================================
405
406 // -------------------------
407 // class SingleConsumerQueue
408 // -------------------------
409
410// CREATORS
411template <class TYPE>
413 bslma::Allocator *basicAllocator)
414: d_impl(basicAllocator)
415{
416}
417
418template <class TYPE>
420 bsl::size_t capacity,
421 bslma::Allocator *basicAllocator)
422: d_impl(capacity, basicAllocator)
423{
424}
425
426// MANIPULATORS
427template <class TYPE>
429{
430 return d_impl.popFront(value);
431}
432
433template <class TYPE>
435{
436 return d_impl.pushBack(value);
437}
438
439template <class TYPE>
441{
442 return d_impl.pushBack(bslmf::MovableRefUtil::move(value));
443}
444
445template <class TYPE>
447{
448 d_impl.removeAll();
449}
450
451template <class TYPE>
453{
454 return d_impl.tryPopFront(value);
455}
456
457template <class TYPE>
459{
460 return d_impl.tryPushBack(value);
461}
462
463template <class TYPE>
465{
466 return d_impl.tryPushBack(bslmf::MovableRefUtil::move(value));
467}
468
469 // Enqueue/Dequeue State
470
471template <class TYPE>
473{
474 d_impl.disablePopFront();
475}
476
477template <class TYPE>
479{
480 d_impl.disablePushBack();
481}
482
483template <class TYPE>
485{
486 d_impl.enablePopFront();
487}
488
489template <class TYPE>
491{
492 d_impl.enablePushBack();
493}
494
495// ACCESSORS
496template <class TYPE>
498{
499 return d_impl.isEmpty();
500}
501
502template <class TYPE>
504{
505 return d_impl.isFull();
506}
507
508template <class TYPE>
510{
511 return d_impl.isPopFrontDisabled();
512}
513
514template <class TYPE>
516{
517 return d_impl.isPushBackDisabled();
518}
519
520template <class TYPE>
522{
523 return d_impl.numElements();
524}
525
526template <class TYPE>
528{
529 return d_impl.waitUntilEmpty();
530}
531
532 // Aspects
533
534template <class TYPE>
536{
537 return d_impl.allocator();
538}
539
540} // close package namespace
541
542
543#endif
544
545// ----------------------------------------------------------------------------
546// Copyright 2019 Bloomberg Finance L.P.
547//
548// Licensed under the Apache License, Version 2.0 (the "License");
549// you may not use this file except in compliance with the License.
550// You may obtain a copy of the License at
551//
552// http://www.apache.org/licenses/LICENSE-2.0
553//
554// Unless required by applicable law or agreed to in writing, software
555// distributed under the License is distributed on an "AS IS" BASIS,
556// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
557// See the License for the specific language governing permissions and
558// limitations under the License.
559// ----------------------------- END-OF-FILE ----------------------------------
560
561/** @} */
562/** @} */
563/** @} */
Definition bdlcc_singleconsumerqueueimpl.h:286
Definition bdlcc_singleconsumerqueue.h:232
bslma::Allocator * allocator() const
Return the allocator used by this object to supply memory.
Definition bdlcc_singleconsumerqueue.h:535
void enablePopFront()
Definition bdlcc_singleconsumerqueue.h:484
void disablePushBack()
Definition bdlcc_singleconsumerqueue.h:478
bool isFull() const
Definition bdlcc_singleconsumerqueue.h:503
bsl::size_t numElements() const
Returns the number of elements currently in this queue.
Definition bdlcc_singleconsumerqueue.h:521
BSLMF_NESTED_TRAIT_DECLARATION(SingleConsumerQueue, bslma::UsesBslmaAllocator)
int pushBack(const TYPE &value)
Definition bdlcc_singleconsumerqueue.h:434
int waitUntilEmpty() const
Definition bdlcc_singleconsumerqueue.h:527
~SingleConsumerQueue()=default
Destroy this object.
bool isEmpty() const
Definition bdlcc_singleconsumerqueue.h:497
void enablePushBack()
Definition bdlcc_singleconsumerqueue.h:490
TYPE value_type
Definition bdlcc_singleconsumerqueue.h:254
bool isPopFrontDisabled() const
Definition bdlcc_singleconsumerqueue.h:509
int tryPushBack(const TYPE &value)
Definition bdlcc_singleconsumerqueue.h:458
bool isPushBackDisabled() const
Definition bdlcc_singleconsumerqueue.h:515
int popFront(TYPE *value)
Definition bdlcc_singleconsumerqueue.h:428
void disablePopFront()
Definition bdlcc_singleconsumerqueue.h:472
void removeAll()
Definition bdlcc_singleconsumerqueue.h:446
int tryPopFront(TYPE *value)
Definition bdlcc_singleconsumerqueue.h:452
@ e_EMPTY
Definition bdlcc_singleconsumerqueue.h:259
@ e_SUCCESS
Definition bdlcc_singleconsumerqueue.h:258
@ e_DISABLED
Definition bdlcc_singleconsumerqueue.h:260
Definition bslma_allocator.h:545
Definition bslmf_movableref.h:752
Definition bslmt_condition.h:220
Definition bslmt_mutex.h:317
#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 bslma_usesbslmaallocator.h:344
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
Definition bsls_atomicoperations.h:836