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