@@ -99,14 +99,16 @@ it from many threads at once :-)
9999
100100Simple example:
101101
102- #include "concurrentqueue.h"
103-
104- moodycamel::ConcurrentQueue<int> q;
105- q.enqueue(25);
106-
107- int item;
108- bool found = q.try_dequeue(item);
109- assert(found && item == 25);
102+ ``` C++
103+ #include " concurrentqueue.h"
104+
105+ moodycamel::ConcurrentQueue<int > q;
106+ q.enqueue(25 );
107+
108+ int item;
109+ bool found = q.try_dequeue(item);
110+ assert (found && item == 25 );
111+ ```
110112
111113Description of basic methods:
112114- ` ConcurrentQueue(size_t initialSizeEstimate) `
@@ -180,31 +182,33 @@ in use either, but it can be easier to coordinate the cleanup.)
180182
181183Blocking example:
182184
183- #include "blockingconcurrentqueue.h"
184-
185- moodycamel::BlockingConcurrentQueue<int> q;
186- std::thread producer([&]() {
187- for (int i = 0; i != 100; ++i) {
188- std::this_thread::sleep_for(std::chrono::milliseconds(i % 10));
189- q.enqueue(i);
190- }
191- });
192- std::thread consumer([&]() {
193- for (int i = 0; i != 100; ++i) {
194- int item;
195- q.wait_dequeue(item);
185+ ``` C++
186+ #include " blockingconcurrentqueue.h"
187+
188+ moodycamel::BlockingConcurrentQueue<int > q;
189+ std::thread producer ([ &] ( ) {
190+ for (int i = 0; i != 100; ++i) {
191+ std::this_thread::sleep_for(std::chrono::milliseconds(i % 10));
192+ q.enqueue(i);
193+ }
194+ });
195+ std::thread consumer([ &] ( ) {
196+ for (int i = 0; i != 100; ++i) {
197+ int item;
198+ q.wait_dequeue(item);
199+ assert(item == i);
200+
201+ if (q.wait_dequeue_timed(item, std::chrono::milliseconds(5))) {
202+ ++i;
196203 assert(item == i);
197-
198- if (q.wait_dequeue_timed(item, std::chrono::milliseconds(5))) {
199- ++i;
200- assert(item == i);
201- }
202204 }
203- });
204- producer.join();
205- consumer.join();
206-
207- assert(q.size_approx() == 0);
205+ }
206+ });
207+ producer.join();
208+ consumer.join();
209+
210+ assert(q.size_approx() == 0);
211+ ```
208212
209213## Advanced features
210214
@@ -216,15 +220,17 @@ You can create a consumer token and/or a producer token for each thread or task
216220(tokens themselves are not thread-safe), and use the methods that accept a token
217221as their first parameter:
218222
219- moodycamel::ConcurrentQueue<int> q;
220-
221- moodycamel::ProducerToken ptok(q);
222- q.enqueue(ptok, 17);
223-
224- moodycamel::ConsumerToken ctok(q);
225- int item;
226- q.try_dequeue(ctok, item);
227- assert(item == 17);
223+ ```C++
224+ moodycamel::ConcurrentQueue<int> q;
225+
226+ moodycamel::ProducerToken ptok(q);
227+ q.enqueue(ptok, 17);
228+
229+ moodycamel::ConsumerToken ctok(q);
230+ int item;
231+ q.try_dequeue(ctok, item);
232+ assert(item == 17);
233+ ```
228234
229235If you happen to know which producer you want to consume from (e.g. in
230236a single-producer, multi-consumer scenario), you can use the ` try_dequeue_from_producer `
@@ -253,16 +259,18 @@ Thanks to the [novel design][blog] of the queue, it's just as easy to enqueue/de
253259items as it is to do one at a time. This means that overhead can be cut drastically for
254260bulk operations. Example syntax:
255261
256- moodycamel::ConcurrentQueue<int> q;
262+ ``` C++
263+ moodycamel::ConcurrentQueue<int > q;
257264
258- int items[] = { 1, 2, 3, 4, 5 };
259- q.enqueue_bulk(items, 5);
260-
261- int results[5]; // Could also be any iterator
262- size_t count = q.try_dequeue_bulk(results, 5);
263- for (size_t i = 0; i != count; ++i) {
264- assert(results[i] == items[i]);
265- }
265+ int items[] = { 1, 2, 3, 4, 5 };
266+ q.enqueue_bulk(items, 5);
267+
268+ int results[ 5] ; // Could also be any iterator
269+ size_t count = q.try_dequeue_bulk(results, 5);
270+ for (size_t i = 0; i != count; ++i) {
271+ assert(results[ i] == items[ i] );
272+ }
273+ ```
266274
267275#### Preallocation (correctly using ` try_enqueue ` )
268276
@@ -289,15 +297,21 @@ integer division (in order for `ceil()` to work).
289297
290298For explicit producers (using tokens to enqueue):
291299
292- (ceil(N / BLOCK_SIZE) + 1) * MAX_NUM_PRODUCERS * BLOCK_SIZE
300+ ``` C++
301+ (ceil(N / BLOCK_SIZE ) + 1 ) * MAX_NUM_PRODUCERS * BLOCK_SIZE
302+ ```
293303
294304For implicit producers (no tokens):
295305
296- (ceil(N / BLOCK_SIZE) - 1 + 2 * MAX_NUM_PRODUCERS) * BLOCK_SIZE
306+ ``` C++
307+ (ceil(N / BLOCK_SIZE ) - 1 + 2 * MAX_NUM_PRODUCERS ) * BLOCK_SIZE
308+ ```
297309
298310When using mixed producer types:
299311
300- ((ceil(N / BLOCK_SIZE) - 1) * (MAX_EXPLICIT_PRODUCERS + 1) + 2 * (MAX_IMPLICIT_PRODUCERS + MAX_EXPLICIT_PRODUCERS)) * BLOCK_SIZE
312+ ``` C++
313+ ((ceil(N / BLOCK_SIZE ) - 1 ) * (MAX_EXPLICIT_PRODUCERS + 1 ) + 2 * (MAX_IMPLICIT_PRODUCERS + MAX_EXPLICIT_PRODUCERS )) * BLOCK_SIZE
314+ ```
301315
302316If these formulas seem rather inconvenient, you can use the constructor overload that accepts the minimum
303317number of elements (` N ` ) and the maximum number of explicit and implicit producers directly, and let it do the
@@ -352,12 +366,14 @@ and the memory allocation and deallocation functions that are to be used by the
352366to providing your own traits is to create a class that inherits from the default traits
353367and override only the values you wish to change. Example:
354368
355- struct MyTraits : public moodycamel::ConcurrentQueueDefaultTraits
356- {
357- static const size_t BLOCK_SIZE = 256; // Use bigger blocks
358- };
359-
360- moodycamel::ConcurrentQueue<int, MyTraits> q;
369+ ``` C++
370+ struct MyTraits : public moodycamel :: ConcurrentQueueDefaultTraits
371+ {
372+ static const size_t BLOCK_SIZE = 256; // Use bigger blocks
373+ };
374+
375+ moodycamel::ConcurrentQueue<int , MyTraits> q;
376+ ```
361377
362378#### How to dequeue types without calling the constructor
363379
@@ -369,44 +385,48 @@ workaround: Create a wrapper class that copies the memory contents of the object
369385is assigned by the queue (a poor man's move, essentially). Note that this only works if
370386the object contains no internal pointers. Example:
371387
372- struct MyObjectMover {
373- inline void operator=(MyObject&& obj) {
374- std::memcpy(data, &obj, sizeof(MyObject));
375-
376- // TODO: Cleanup obj so that when it's destructed by the queue
377- // it doesn't corrupt the data of the object we just moved it into
378- }
388+ ``` C++
389+ struct MyObjectMover {
390+ inline void operator=(MyObject&& obj) {
391+ std::memcpy(data, &obj, sizeof(MyObject));
392+
393+ // TODO: Cleanup obj so that when it's destructed by the queue
394+ // it doesn't corrupt the data of the object we just moved it into
395+ }
379396
380- inline MyObject& obj() { return *reinterpret_cast<MyObject*>(data); }
397+ inline MyObject& obj() { return *reinterpret_cast<MyObject*>(data); }
381398
382- private:
383- align(alignof(MyObject)) char data[sizeof(MyObject)];
384- };
399+ private:
400+ align (alignof(MyObject)) char data[ sizeof(MyObject)] ;
401+ };
402+ ```
385403
386404A less dodgy alternative, if moves are cheap but default construction is not, is to use a
387405wrapper that defers construction until the object is assigned, enabling use of the move
388406constructor:
389407
390- struct MyObjectMover {
391- inline void operator=(MyObject&& x) {
392- new (data) MyObject(std::move(x));
393- created = true;
394- }
408+ ```C++
409+ struct MyObjectMover {
410+ inline void operator=(MyObject&& x) {
411+ new (data) MyObject(std::move(x));
412+ created = true;
413+ }
395414
396- inline MyObject& obj() {
397- assert(created);
398- return *reinterpret_cast<MyObject*>(data);
399- }
415+ inline MyObject& obj() {
416+ assert(created);
417+ return *reinterpret_cast<MyObject*>(data);
418+ }
400419
401- ~MyObjectMover() {
402- if (created)
403- obj().~MyObject();
404- }
420+ ~MyObjectMover() {
421+ if (created)
422+ obj().~MyObject();
423+ }
405424
406- private:
407- align(alignof(MyObject)) char data[sizeof(MyObject)];
408- bool created = false;
409- };
425+ private:
426+ align(alignof(MyObject)) char data[sizeof(MyObject)];
427+ bool created = false;
428+ };
429+ ```
410430
411431## Samples
412432
@@ -419,9 +439,11 @@ See my blog post for some [benchmark results][benchmarks] (including versus `boo
419439or run the benchmarks yourself (requires MinGW and certain GnuWin32 utilities to build on Windows, or a recent
420440g++ on Linux):
421441
422- cd build
423- make benchmarks
424- bin/benchmarks
442+ ``` Shell
443+ cd build
444+ make benchmarks
445+ bin/benchmarks
446+ ```
425447
426448The short version of the benchmarks is that it's so fast (especially the bulk methods), that if you're actually
427449using the queue to * do* anything, the queue won't be your bottleneck.
@@ -443,11 +465,13 @@ a unit test for it can be cooked up.) Just open an issue on GitHub.
443465## Using vcpkg
444466You can download and install ` moodycamel::ConcurrentQueue ` using the [ vcpkg] ( https://github.com/Microsoft/vcpkg ) dependency manager:
445467
446- git clone https://github.com/Microsoft/vcpkg.git
447- cd vcpkg
448- ./bootstrap-vcpkg.sh
449- ./vcpkg integrate install
450- vcpkg install concurrentqueue
468+ ``` Shell
469+ git clone https://github.com/Microsoft/vcpkg.git
470+ cd vcpkg
471+ ./bootstrap-vcpkg.sh
472+ ./vcpkg integrate install
473+ vcpkg install concurrentqueue
474+ ```
451475
452476The ` moodycamel::ConcurrentQueue ` port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [ create an issue or pull request] ( https://github.com/Microsoft/vcpkg ) on the vcpkg repository.
453477
0 commit comments