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