[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files\n*.slo\n*.lo\n*.o\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n\n# build files\nCMakeCache.txt\nCMakeFiles/\nMakefile\nbuild/\ncmake_install.cmake"
  },
  {
    "path": "CMakeLists.txt",
    "content": "CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0)\nset(PROJECT_NAME_STR queue-test)\nproject(${PROJECT_NAME_STR} C CXX)\n\n#-------------------------------------------------------------------------------\n# The version number\n#-------------------------------------------------------------------------------\nset (queue-test_VERSION_MAJOR 0)\nset (queue-test_VERSION_MINOR 2)\nset (queue-test_VERSION_STRING ${queue-test_VERSION_MAJOR}.${queue-test_VERSION_MINOR})\n\n#-------------------------------------------------------------------------------\n# Locate the threading lib and add it to the linked libs\n#-------------------------------------------------------------------------------\nfind_package(Threads)\nset(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT})\n\n#-------------------------------------------------------------------------------\n# example and benchmark program\n#-------------------------------------------------------------------------------\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY \"build/bin/\")\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/bin)\nset(PROJECT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)\n\ninclude_directories(${INCLUDES} ${PROJECT_INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/src)\nfile(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/src/*.cpp)\nadd_executable(${PROJECT_NAME} ${SRC_FILES})\ntarget_link_libraries(${PROJECT_NAME} ${LIBS})\n\n#-------------------------------------------------------------------------------\n# Set compiler flags\n#-------------------------------------------------------------------------------\nset(PROJECT_COMPILER_FLAGS ${PROJECT_COMPILER_FLAGS} \"${CMAKE_CXX_FLAGS} -O2 -std=c++11 -fPIC -Wall -pedantic -Wextra -Werror -Wno-long-long\")\n\nset_property(\n  TARGET ${PROJECT_NAME}\n  APPEND PROPERTY COMPILE_FLAGS ${PROJECT_COMPILER_FLAGS})\n"
  },
  {
    "path": "LICENSE",
    "content": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, compile, sell, or\ndistribute this software, either in source code form or as a compiled\nbinary, for any purpose, commercial or non-commercial, and by any\nmeans.\n\nIn jurisdictions that recognize copyright laws, the author or authors\nof this software dedicate any and all copyright interest in the\nsoftware to the public domain. We make this dedication for the benefit\nof the public at large and to the detriment of our heirs and\nsuccessors. We intend this dedication to be an overt act of\nrelinquishment in perpetuity of all present and future rights to this\nsoftware under copyright law.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\nFor more information, please refer to <http://unlicense.org>\n"
  },
  {
    "path": "README.md",
    "content": "Lock Free Queues\n==================\n\nPublic domain implementation of four different lock free queues:\n  * SPSC lock free dynamic queue which requires a memory allocation with each insert.\n  * MPSC lock free dynamic queue which requires a memory allocation with each insert.\n  * SPSC wait free bound queue/ring buffer which which uses a fixed size pre-allocated buffer.\n  * MPMC lock free bound queue/ring buffer which which uses a fixed size pre-allocated buffer.\n\n## Performance\nThese number are on my Early 2013 Retina Macbook Pro (2.7 GHz i7). The latency variability of memory allocation can have a signifigant impact on the dynamic queues, sometimes halving throughput.\n\n  Queue        | Throughput  \n  :----------- | :-----------\n  SPSC dynamic | 8 million   \n  MPSC dynamic | 8 million   \n  SPSC fixed   | 200 million \n  MPMC fixed   | 54 million  \n"
  },
  {
    "path": "include/mpmc-bounded-queue.hpp",
    "content": "// This is free and unencumbered software released into the public domain.\n\n// Anyone is free to copy, modify, publish, use, compile, sell, or\n// distribute this software, either in source code form or as a compiled\n// binary, for any purpose, commercial or non-commercial, and by any\n// means.\n\n// In jurisdictions that recognize copyright laws, the author or authors\n// of this software dedicate any and all copyright interest in the\n// software to the public domain. We make this dedication for the benefit\n// of the public at large and to the detriment of our heirs and\n// successors. We intend this dedication to be an overt act of\n// relinquishment in perpetuity of all present and future rights to this\n// software under copyright law.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n// OTHER DEALINGS IN THE SOFTWARE.\n\n// For more information, please refer to <http://unlicense.org/>\n\n// Implementation of Dmitry Vyukov's MPMC algorithm\n// http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue\n\n\n#ifndef __MPMC_BOUNDED_QUEUE_INCLUDED__\n#define __MPMC_BOUNDED_QUEUE_INCLUDED__\n\n#include <atomic>\n#include <assert.h>\n\ntemplate<typename T>\nclass mpmc_bounded_queue_t\n{\npublic:\n\n    mpmc_bounded_queue_t(\n        size_t size) :\n        _size(size),\n        _mask(size - 1),\n        _buffer(reinterpret_cast<node_t*>(new aligned_node_t[_size])),\n        _head_seq(0),\n        _tail_seq(0)\n    {\n        // make sure it's a power of 2\n        assert((_size != 0) && ((_size & (~_size + 1)) == _size));\n\n        // populate the sequence initial values\n        for (size_t i = 0; i < _size; ++i) {\n            _buffer[i].seq.store(i, std::memory_order_relaxed);\n        }\n    }\n\n    ~mpmc_bounded_queue_t()\n    {\n        delete[] _buffer;\n    }\n\n    bool\n    enqueue(\n        const T& data)\n    {\n        // _head_seq only wraps at MAX(_head_seq) instead we use a mask to convert the sequence to an array index\n        // this is why the ring buffer must be a size which is a power of 2. this also allows the sequence to double as a ticket/lock.\n        size_t  head_seq = _head_seq.load(std::memory_order_relaxed);\n\n        for (;;) {\n            node_t*  node     = &_buffer[head_seq & _mask];\n            size_t   node_seq = node->seq.load(std::memory_order_acquire);\n            intptr_t dif      = (intptr_t) node_seq - (intptr_t) head_seq;\n\n            // if seq and head_seq are the same then it means this slot is empty\n            if (dif == 0) {\n                // claim our spot by moving head\n                // if head isn't the same as we last checked then that means someone beat us to the punch\n                // weak compare is faster, but can return spurious results\n                // which in this instance is OK, because it's in the loop\n                if (_head_seq.compare_exchange_weak(head_seq, head_seq + 1, std::memory_order_relaxed)) {\n                    // set the data\n                    node->data = data;\n                    // increment the sequence so that the tail knows it's accessible\n                    node->seq.store(head_seq + 1, std::memory_order_release);\n                    return true;\n                }\n            }\n            else if (dif < 0) {\n                // if seq is less than head seq then it means this slot is full and therefore the buffer is full\n                return false;\n            }\n            else {\n                // under normal circumstances this branch should never be taken\n                head_seq = _head_seq.load(std::memory_order_relaxed);\n            }\n        }\n\n        // never taken\n        return false;\n    }\n\n    bool\n    dequeue(\n        T& data)\n    {\n        size_t       tail_seq = _tail_seq.load(std::memory_order_relaxed);\n\n        for (;;) {\n            node_t*  node     = &_buffer[tail_seq & _mask];\n            size_t   node_seq = node->seq.load(std::memory_order_acquire);\n            intptr_t dif      = (intptr_t) node_seq - (intptr_t)(tail_seq + 1);\n\n            // if seq and head_seq are the same then it means this slot is empty\n            if (dif == 0) {\n                // claim our spot by moving head\n                // if head isn't the same as we last checked then that means someone beat us to the punch\n                // weak compare is faster, but can return spurious results\n                // which in this instance is OK, because it's in the loop\n                if (_tail_seq.compare_exchange_weak(tail_seq, tail_seq + 1, std::memory_order_relaxed)) {\n                    // set the output\n                    data = node->data;\n                    // set the sequence to what the head sequence should be next time around\n                    node->seq.store(tail_seq + _mask + 1, std::memory_order_release);\n                    return true;\n                }\n            }\n            else if (dif < 0) {\n                // if seq is less than head seq then it means this slot is full and therefore the buffer is full\n                return false;\n            }\n            else {\n                // under normal circumstances this branch should never be taken\n                tail_seq = _tail_seq.load(std::memory_order_relaxed);\n            }\n        }\n\n        // never taken\n        return false;\n    }\n\nprivate:\n\n    struct node_t\n    {\n        T                     data;\n        std::atomic<size_t>   seq;\n    };\n\n    typedef typename std::aligned_storage<sizeof(node_t), std::alignment_of<node_t>::value>::type aligned_node_t;\n    typedef char cache_line_pad_t[64]; // it's either 32 or 64 so 64 is good enough\n\n    cache_line_pad_t    _pad0;\n    const size_t        _size;\n    const size_t        _mask;\n    node_t* const       _buffer;\n    cache_line_pad_t    _pad1;\n    std::atomic<size_t> _head_seq;\n    cache_line_pad_t    _pad2;\n    std::atomic<size_t> _tail_seq;\n    cache_line_pad_t    _pad3;\n\n    mpmc_bounded_queue_t(const mpmc_bounded_queue_t&) {}\n    void operator=(const mpmc_bounded_queue_t&) {}\n};\n\n#endif\n"
  },
  {
    "path": "include/mpsc-queue.hpp",
    "content": "// This is free and unencumbered software released into the public domain.\n\n// Anyone is free to copy, modify, publish, use, compile, sell, or\n// distribute this software, either in source code form or as a compiled\n// binary, for any purpose, commercial or non-commercial, and by any\n// means.\n\n// In jurisdictions that recognize copyright laws, the author or authors\n// of this software dedicate any and all copyright interest in the\n// software to the public domain. We make this dedication for the benefit\n// of the public at large and to the detriment of our heirs and\n// successors. We intend this dedication to be an overt act of\n// relinquishment in perpetuity of all present and future rights to this\n// software under copyright law.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n// OTHER DEALINGS IN THE SOFTWARE.\n\n// For more information, please refer to <http://unlicense.org/>\n\n// C++ implementation of Dmitry Vyukov's non-intrusive lock free unbound MPSC queue\n// http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue\n\n#ifndef __MPSC_BOUNDED_QUEUE_INCLUDED__\n#define __MPSC_BOUNDED_QUEUE_INCLUDED__\n\n#include <atomic>\n#include <assert.h>\n\ntemplate<typename T>\nclass mpsc_queue_t\n{\npublic:\n\n    mpsc_queue_t() :\n        _head(reinterpret_cast<buffer_node_t*>(new buffer_node_aligned_t)),\n        _tail(_head.load(std::memory_order_relaxed))\n    {\n        buffer_node_t* front = _head.load(std::memory_order_relaxed);\n        front->next.store(NULL, std::memory_order_relaxed);\n    }\n\n    ~mpsc_queue_t()\n    {\n        T output;\n        while (this->dequeue(output)) {}\n        buffer_node_t* front = _head.load(std::memory_order_relaxed);\n        delete front;\n    }\n\n    void\n    enqueue(\n        const T& input)\n    {\n        buffer_node_t* node = reinterpret_cast<buffer_node_t*>(new buffer_node_aligned_t);\n        node->data = input;\n        node->next.store(NULL, std::memory_order_relaxed);\n\n        buffer_node_t* prev_head = _head.exchange(node, std::memory_order_acq_rel);\n        prev_head->next.store(node, std::memory_order_release);\n    }\n\n    bool\n    dequeue(\n        T& output)\n    {\n        buffer_node_t* tail = _tail.load(std::memory_order_relaxed);\n        buffer_node_t* next = tail->next.load(std::memory_order_acquire);\n\n        if (next == NULL) {\n            return false;\n        }\n\n        output = next->data;\n        _tail.store(next, std::memory_order_release);\n        delete tail;\n        return true;\n    }\n\n\nprivate:\n\n    struct buffer_node_t\n    {\n        T                           data;\n        std::atomic<buffer_node_t*> next;\n    };\n\n    typedef typename std::aligned_storage<sizeof(buffer_node_t), std::alignment_of<buffer_node_t>::value>::type buffer_node_aligned_t;\n\n    std::atomic<buffer_node_t*> _head;\n    std::atomic<buffer_node_t*> _tail;\n\n    mpsc_queue_t(const mpsc_queue_t&) {}\n    void operator=(const mpsc_queue_t&) {}\n};\n\n#endif\n"
  },
  {
    "path": "include/spsc-bounded-queue.hpp",
    "content": "// This is free and unencumbered software released into the public domain.\n\n// Anyone is free to copy, modify, publish, use, compile, sell, or\n// distribute this software, either in source code form or as a compiled\n// binary, for any purpose, commercial or non-commercial, and by any\n// means.\n\n// In jurisdictions that recognize copyright laws, the author or authors\n// of this software dedicate any and all copyright interest in the\n// software to the public domain. We make this dedication for the benefit\n// of the public at large and to the detriment of our heirs and\n// successors. We intend this dedication to be an overt act of\n// relinquishment in perpetuity of all present and future rights to this\n// software under copyright law.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n// OTHER DEALINGS IN THE SOFTWARE.\n\n// For more information, please refer to <http://unlicense.org/>\n\n// Note:\n// A combination of the algorithms described by the circular buffers\n// documentation found in the Linux kernel, and the bounded MPMC queue\n// by Dmitry Vyukov[1]. Implemented in pure C++11. Should work across\n// most CPU architectures.\n//\n// [1] http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue\n\n#ifndef __SPSC_BOUNDED_QUEUE_INCLUDED__\n#define __SPSC_BOUNDED_QUEUE_INCLUDED__\n\n#include <atomic>\n#include <assert.h>\n\ntemplate<typename T>\nclass spsc_bounded_queue_t\n{\npublic:\n\n    spsc_bounded_queue_t(\n        size_t size) :\n        _size(size),\n        _mask(size - 1),\n        _buffer(reinterpret_cast<T*>(new aligned_t[_size + 1])), // need one extra element for a guard\n        _head(0),\n        _tail(0)\n    {\n        // make sure it's a power of 2\n        assert((_size != 0) && ((_size & (~_size + 1)) == _size));\n    }\n\n    ~spsc_bounded_queue_t()\n    {\n        delete[] _buffer;\n    }\n\n    bool\n    enqueue(\n        T& input)\n    {\n        const size_t head = _head.load(std::memory_order_relaxed);\n\n        if (((_tail.load(std::memory_order_acquire) - (head + 1)) & _mask) >= 1) {\n            _buffer[head & _mask] = input;\n            _head.store(head + 1, std::memory_order_release);\n            return true;\n        }\n        return false;\n    }\n\n    bool\n    dequeue(\n        T& output)\n    {\n        const size_t tail = _tail.load(std::memory_order_relaxed);\n\n        if (((_head.load(std::memory_order_acquire) - tail) & _mask) >= 1) {\n            output = _buffer[_tail & _mask];\n            _tail.store(tail + 1, std::memory_order_release);\n            return true;\n        }\n        return false;\n    }\n\n\nprivate:\n\n    typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type aligned_t;\n    typedef char cache_line_pad_t[64];\n\n    cache_line_pad_t    _pad0;\n    const size_t        _size;\n    const size_t        _mask;\n    T* const            _buffer;\n\n    cache_line_pad_t    _pad1;\n    std::atomic<size_t> _head;\n\n    cache_line_pad_t    _pad2;\n    std::atomic<size_t> _tail;\n\n    spsc_bounded_queue_t(const spsc_bounded_queue_t&) {}\n    void operator=(const spsc_bounded_queue_t&) {}\n};\n\n#endif\n"
  },
  {
    "path": "include/spsc-queue.hpp",
    "content": "// This is free and unencumbered software released into the public domain.\n\n// Anyone is free to copy, modify, publish, use, compile, sell, or\n// distribute this software, either in source code form or as a compiled\n// binary, for any purpose, commercial or non-commercial, and by any\n// means.\n\n// In jurisdictions that recognize copyright laws, the author or authors\n// of this software dedicate any and all copyright interest in the\n// software to the public domain. We make this dedication for the benefit\n// of the public at large and to the detriment of our heirs and\n// successors. We intend this dedication to be an overt act of\n// relinquishment in perpetuity of all present and future rights to this\n// software under copyright law.\n\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n// OTHER DEALINGS IN THE SOFTWARE.\n\n// For more information, please refer to <http://unlicense.org/>\n\n\n// non-intrusive lock free unbounded SPSC queue\n// the algorithm was taken from the blog post below, and converted to C++11\n// http://cbloomrants.blogspot.com/2009/02/02-26-09-low-level-threading-part-51.html\n\n#ifndef __SPSC_QUEUE_INCLUDED__\n#define __SPSC_QUEUE_INCLUDED__\n\n#include <atomic>\n\ntemplate<typename T>\nclass spsc_queue_t\n{\npublic:\n\n    spsc_queue_t() :\n        _head(reinterpret_cast<node_t*>(new node_aligned_t)),\n        _tail(_head)\n    {\n        _head->next = NULL;\n    }\n\n    ~spsc_queue_t()\n    {\n        T output;\n        while (this->dequeue(output)) {}\n        delete _head;\n    }\n\n    void\n    enqueue(\n        const T& input)\n    {\n        node_t* node = reinterpret_cast<node_t*>(new node_aligned_t);\n        node->data = input;\n        node->next = NULL;\n\n        std::atomic_thread_fence(std::memory_order_acq_rel);\n        _head->next = node;\n        _head = node;\n    }\n\n    bool\n    dequeue(\n        T& output)\n    {\n        std::atomic_thread_fence(std::memory_order_consume);\n        if (!_tail->next) {\n            return false;\n        }\n\n        output = _tail->next->data;\n        std::atomic_thread_fence(std::memory_order_acq_rel);\n        _back = _tail;\n        _tail = _back->next;\n\n        delete _back;\n        return true;\n    }\n\n\nprivate:\n\n    struct node_t\n    {\n        node_t* next;\n        T       data;\n    };\n\n    typedef typename std::aligned_storage<sizeof(node_t), std::alignment_of<node_t>::value>::type node_aligned_t;\n\n    node_t* _head;\n    char    _cache_line[64];\n    node_t* _tail;\n    node_t* _back;\n\n    spsc_queue_t(const spsc_queue_t&) {}\n    void operator=(const spsc_queue_t&) {}\n};\n\n#endif\n"
  },
  {
    "path": "src/main.cpp",
    "content": "#include <iostream>\n#include <thread>\n\n#include \"spsc-queue.hpp\"\n#include \"mpsc-queue.hpp\"\n#include \"spsc-bounded-queue.hpp\"\n#include \"mpmc-bounded-queue.hpp\"\n\n#define COUNT 100000000\n\ntemplate<typename T>\nvoid\nconsumer_func(\n    T* queue)\n{\n    size_t count = COUNT;\n    size_t value = 0;\n\n    while (count > 0) {\n        if (queue->dequeue(value)) {\n            --count;\n        }\n    }\n}\n\ntemplate<typename T>\nvoid\nbounded_producer_func(\n    T* queue)\n{\n    size_t count = COUNT;\n    while (count > 0) {\n        if (queue->enqueue(count)) {\n            --count;\n        }\n    }\n}\n\ntemplate<typename T>\nvoid\nproducer_func(\n    T* queue)\n{\n    for (int count = 0; count < COUNT; ++count) {\n        queue->enqueue(count);\n    }\n}\n\ntemplate<typename T>\nlong double\nrun_test(\n    T producer_func,\n    T consumer_func)\n{\n    typedef std::chrono::high_resolution_clock clock_t;\n    typedef std::chrono::time_point<clock_t> time_t;\n    time_t start;\n    time_t end;\n\n    start = clock_t::now();\n    std::thread producer(producer_func);\n    std::thread consumer(consumer_func);\n\n    producer.join();\n    consumer.join();\n    end = clock_t::now();\n\n    return\n        (end - start).count()\n        * ((double) std::chrono::high_resolution_clock::period::num\n           / std::chrono::high_resolution_clock::period::den);\n}\n\nint\nmain()\n{\n    {\n        typedef spsc_bounded_queue_t<size_t> queue_t;\n        queue_t queue(65536);\n        long double seconds = run_test(std::bind(&bounded_producer_func<queue_t>, &queue),\n                                       std::bind(&consumer_func<queue_t>, &queue));\n\n        std::cout << \"SPSC bound queue completed \"\n                  << COUNT\n                  << \" iterations in \"\n                  << seconds\n                  << \" seconds. \"\n                  << ((long double) COUNT / seconds) / 1000000\n                  << \" million enqueue/dequeue pairs per second.\"\n                  << std::endl;\n    }\n\n    {\n        typedef mpmc_bounded_queue_t<size_t> queue_t;\n        queue_t queue(65536);\n        long double seconds = run_test(std::bind(&bounded_producer_func<queue_t>, &queue),\n                                       std::bind(&consumer_func<queue_t>, &queue));\n\n        std::cout << \"MPMC bound queue completed \"\n                  << COUNT\n                  << \" iterations in \"\n                  << seconds\n                  << \" seconds. \"\n                  << ((long double) COUNT / seconds) / 1000000\n                  << \" million enqueue/dequeue pairs per second.\"\n                  << std::endl;\n    }\n\n    {\n        typedef spsc_queue_t<size_t> queue_t;\n        queue_t queue;\n        long double seconds = run_test(std::bind(&producer_func<queue_t>, &queue),\n                                       std::bind(&consumer_func<queue_t>, &queue));\n\n        std::cout << \"SPSC dynamic queue completed \"\n                  << COUNT\n                  << \" iterations in \"\n                  << seconds\n                  << \" seconds. \"\n                  << ((long double) COUNT / seconds) / 1000000\n                  << \" million enqueue/dequeue pairs per second.\"\n                  << std::endl;\n    }\n\n    {\n        typedef mpsc_queue_t<size_t> queue_t;\n        queue_t queue;\n        long double seconds = run_test(std::bind(&producer_func<queue_t>, &queue),\n                                       std::bind(&consumer_func<queue_t>, &queue));\n\n        std::cout << \"MPSC dynamic queue completed \"\n                  << COUNT\n                  << \" iterations in \"\n                  << seconds\n                  << \" seconds. \"\n                  << ((long double) COUNT / seconds) / 1000000\n                  << \" million enqueue/dequeue pairs per second.\"\n                  << std::endl;\n    }\n\n    return 0;\n}\n"
  }
]