Repository: mstump/queues
Branch: master
Commit: 319c253d68f1
Files: 9
Total size: 23.3 KB
Directory structure:
gitextract_idzpu85s/
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── include/
│ ├── mpmc-bounded-queue.hpp
│ ├── mpsc-queue.hpp
│ ├── spsc-bounded-queue.hpp
│ └── spsc-queue.hpp
└── src/
└── main.cpp
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Compiled Object files
*.slo
*.lo
*.o
# Compiled Dynamic libraries
*.so
*.dylib
# Compiled Static libraries
*.lai
*.la
*.a
# build files
CMakeCache.txt
CMakeFiles/
Makefile
build/
cmake_install.cmake
================================================
FILE: CMakeLists.txt
================================================
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0)
set(PROJECT_NAME_STR queue-test)
project(${PROJECT_NAME_STR} C CXX)
#-------------------------------------------------------------------------------
# The version number
#-------------------------------------------------------------------------------
set (queue-test_VERSION_MAJOR 0)
set (queue-test_VERSION_MINOR 2)
set (queue-test_VERSION_STRING ${queue-test_VERSION_MAJOR}.${queue-test_VERSION_MINOR})
#-------------------------------------------------------------------------------
# Locate the threading lib and add it to the linked libs
#-------------------------------------------------------------------------------
find_package(Threads)
set(LIBS ${LIBS} ${CMAKE_THREAD_LIBS_INIT})
#-------------------------------------------------------------------------------
# example and benchmark program
#-------------------------------------------------------------------------------
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "build/bin/")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/bin)
set(PROJECT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
include_directories(${INCLUDES} ${PROJECT_INCLUDE_DIR} ${PROJECT_SOURCE_DIR}/src)
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/src/*.cpp)
add_executable(${PROJECT_NAME} ${SRC_FILES})
target_link_libraries(${PROJECT_NAME} ${LIBS})
#-------------------------------------------------------------------------------
# Set compiler flags
#-------------------------------------------------------------------------------
set(PROJECT_COMPILER_FLAGS ${PROJECT_COMPILER_FLAGS} "${CMAKE_CXX_FLAGS} -O2 -std=c++11 -fPIC -Wall -pedantic -Wextra -Werror -Wno-long-long")
set_property(
TARGET ${PROJECT_NAME}
APPEND PROPERTY COMPILE_FLAGS ${PROJECT_COMPILER_FLAGS})
================================================
FILE: LICENSE
================================================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>
================================================
FILE: README.md
================================================
Lock Free Queues
==================
Public domain implementation of four different lock free queues:
* SPSC lock free dynamic queue which requires a memory allocation with each insert.
* MPSC lock free dynamic queue which requires a memory allocation with each insert.
* SPSC wait free bound queue/ring buffer which which uses a fixed size pre-allocated buffer.
* MPMC lock free bound queue/ring buffer which which uses a fixed size pre-allocated buffer.
## Performance
These 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.
Queue | Throughput
:----------- | :-----------
SPSC dynamic | 8 million
MPSC dynamic | 8 million
SPSC fixed | 200 million
MPMC fixed | 54 million
================================================
FILE: include/mpmc-bounded-queue.hpp
================================================
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// For more information, please refer to <http://unlicense.org/>
// Implementation of Dmitry Vyukov's MPMC algorithm
// http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
#ifndef __MPMC_BOUNDED_QUEUE_INCLUDED__
#define __MPMC_BOUNDED_QUEUE_INCLUDED__
#include <atomic>
#include <assert.h>
template<typename T>
class mpmc_bounded_queue_t
{
public:
mpmc_bounded_queue_t(
size_t size) :
_size(size),
_mask(size - 1),
_buffer(reinterpret_cast<node_t*>(new aligned_node_t[_size])),
_head_seq(0),
_tail_seq(0)
{
// make sure it's a power of 2
assert((_size != 0) && ((_size & (~_size + 1)) == _size));
// populate the sequence initial values
for (size_t i = 0; i < _size; ++i) {
_buffer[i].seq.store(i, std::memory_order_relaxed);
}
}
~mpmc_bounded_queue_t()
{
delete[] _buffer;
}
bool
enqueue(
const T& data)
{
// _head_seq only wraps at MAX(_head_seq) instead we use a mask to convert the sequence to an array index
// 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.
size_t head_seq = _head_seq.load(std::memory_order_relaxed);
for (;;) {
node_t* node = &_buffer[head_seq & _mask];
size_t node_seq = node->seq.load(std::memory_order_acquire);
intptr_t dif = (intptr_t) node_seq - (intptr_t) head_seq;
// if seq and head_seq are the same then it means this slot is empty
if (dif == 0) {
// claim our spot by moving head
// if head isn't the same as we last checked then that means someone beat us to the punch
// weak compare is faster, but can return spurious results
// which in this instance is OK, because it's in the loop
if (_head_seq.compare_exchange_weak(head_seq, head_seq + 1, std::memory_order_relaxed)) {
// set the data
node->data = data;
// increment the sequence so that the tail knows it's accessible
node->seq.store(head_seq + 1, std::memory_order_release);
return true;
}
}
else if (dif < 0) {
// if seq is less than head seq then it means this slot is full and therefore the buffer is full
return false;
}
else {
// under normal circumstances this branch should never be taken
head_seq = _head_seq.load(std::memory_order_relaxed);
}
}
// never taken
return false;
}
bool
dequeue(
T& data)
{
size_t tail_seq = _tail_seq.load(std::memory_order_relaxed);
for (;;) {
node_t* node = &_buffer[tail_seq & _mask];
size_t node_seq = node->seq.load(std::memory_order_acquire);
intptr_t dif = (intptr_t) node_seq - (intptr_t)(tail_seq + 1);
// if seq and head_seq are the same then it means this slot is empty
if (dif == 0) {
// claim our spot by moving head
// if head isn't the same as we last checked then that means someone beat us to the punch
// weak compare is faster, but can return spurious results
// which in this instance is OK, because it's in the loop
if (_tail_seq.compare_exchange_weak(tail_seq, tail_seq + 1, std::memory_order_relaxed)) {
// set the output
data = node->data;
// set the sequence to what the head sequence should be next time around
node->seq.store(tail_seq + _mask + 1, std::memory_order_release);
return true;
}
}
else if (dif < 0) {
// if seq is less than head seq then it means this slot is full and therefore the buffer is full
return false;
}
else {
// under normal circumstances this branch should never be taken
tail_seq = _tail_seq.load(std::memory_order_relaxed);
}
}
// never taken
return false;
}
private:
struct node_t
{
T data;
std::atomic<size_t> seq;
};
typedef typename std::aligned_storage<sizeof(node_t), std::alignment_of<node_t>::value>::type aligned_node_t;
typedef char cache_line_pad_t[64]; // it's either 32 or 64 so 64 is good enough
cache_line_pad_t _pad0;
const size_t _size;
const size_t _mask;
node_t* const _buffer;
cache_line_pad_t _pad1;
std::atomic<size_t> _head_seq;
cache_line_pad_t _pad2;
std::atomic<size_t> _tail_seq;
cache_line_pad_t _pad3;
mpmc_bounded_queue_t(const mpmc_bounded_queue_t&) {}
void operator=(const mpmc_bounded_queue_t&) {}
};
#endif
================================================
FILE: include/mpsc-queue.hpp
================================================
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// For more information, please refer to <http://unlicense.org/>
// C++ implementation of Dmitry Vyukov's non-intrusive lock free unbound MPSC queue
// http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue
#ifndef __MPSC_BOUNDED_QUEUE_INCLUDED__
#define __MPSC_BOUNDED_QUEUE_INCLUDED__
#include <atomic>
#include <assert.h>
template<typename T>
class mpsc_queue_t
{
public:
mpsc_queue_t() :
_head(reinterpret_cast<buffer_node_t*>(new buffer_node_aligned_t)),
_tail(_head.load(std::memory_order_relaxed))
{
buffer_node_t* front = _head.load(std::memory_order_relaxed);
front->next.store(NULL, std::memory_order_relaxed);
}
~mpsc_queue_t()
{
T output;
while (this->dequeue(output)) {}
buffer_node_t* front = _head.load(std::memory_order_relaxed);
delete front;
}
void
enqueue(
const T& input)
{
buffer_node_t* node = reinterpret_cast<buffer_node_t*>(new buffer_node_aligned_t);
node->data = input;
node->next.store(NULL, std::memory_order_relaxed);
buffer_node_t* prev_head = _head.exchange(node, std::memory_order_acq_rel);
prev_head->next.store(node, std::memory_order_release);
}
bool
dequeue(
T& output)
{
buffer_node_t* tail = _tail.load(std::memory_order_relaxed);
buffer_node_t* next = tail->next.load(std::memory_order_acquire);
if (next == NULL) {
return false;
}
output = next->data;
_tail.store(next, std::memory_order_release);
delete tail;
return true;
}
private:
struct buffer_node_t
{
T data;
std::atomic<buffer_node_t*> next;
};
typedef typename std::aligned_storage<sizeof(buffer_node_t), std::alignment_of<buffer_node_t>::value>::type buffer_node_aligned_t;
std::atomic<buffer_node_t*> _head;
std::atomic<buffer_node_t*> _tail;
mpsc_queue_t(const mpsc_queue_t&) {}
void operator=(const mpsc_queue_t&) {}
};
#endif
================================================
FILE: include/spsc-bounded-queue.hpp
================================================
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// For more information, please refer to <http://unlicense.org/>
// Note:
// A combination of the algorithms described by the circular buffers
// documentation found in the Linux kernel, and the bounded MPMC queue
// by Dmitry Vyukov[1]. Implemented in pure C++11. Should work across
// most CPU architectures.
//
// [1] http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
#ifndef __SPSC_BOUNDED_QUEUE_INCLUDED__
#define __SPSC_BOUNDED_QUEUE_INCLUDED__
#include <atomic>
#include <assert.h>
template<typename T>
class spsc_bounded_queue_t
{
public:
spsc_bounded_queue_t(
size_t size) :
_size(size),
_mask(size - 1),
_buffer(reinterpret_cast<T*>(new aligned_t[_size + 1])), // need one extra element for a guard
_head(0),
_tail(0)
{
// make sure it's a power of 2
assert((_size != 0) && ((_size & (~_size + 1)) == _size));
}
~spsc_bounded_queue_t()
{
delete[] _buffer;
}
bool
enqueue(
T& input)
{
const size_t head = _head.load(std::memory_order_relaxed);
if (((_tail.load(std::memory_order_acquire) - (head + 1)) & _mask) >= 1) {
_buffer[head & _mask] = input;
_head.store(head + 1, std::memory_order_release);
return true;
}
return false;
}
bool
dequeue(
T& output)
{
const size_t tail = _tail.load(std::memory_order_relaxed);
if (((_head.load(std::memory_order_acquire) - tail) & _mask) >= 1) {
output = _buffer[_tail & _mask];
_tail.store(tail + 1, std::memory_order_release);
return true;
}
return false;
}
private:
typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type aligned_t;
typedef char cache_line_pad_t[64];
cache_line_pad_t _pad0;
const size_t _size;
const size_t _mask;
T* const _buffer;
cache_line_pad_t _pad1;
std::atomic<size_t> _head;
cache_line_pad_t _pad2;
std::atomic<size_t> _tail;
spsc_bounded_queue_t(const spsc_bounded_queue_t&) {}
void operator=(const spsc_bounded_queue_t&) {}
};
#endif
================================================
FILE: include/spsc-queue.hpp
================================================
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// For more information, please refer to <http://unlicense.org/>
// non-intrusive lock free unbounded SPSC queue
// the algorithm was taken from the blog post below, and converted to C++11
// http://cbloomrants.blogspot.com/2009/02/02-26-09-low-level-threading-part-51.html
#ifndef __SPSC_QUEUE_INCLUDED__
#define __SPSC_QUEUE_INCLUDED__
#include <atomic>
template<typename T>
class spsc_queue_t
{
public:
spsc_queue_t() :
_head(reinterpret_cast<node_t*>(new node_aligned_t)),
_tail(_head)
{
_head->next = NULL;
}
~spsc_queue_t()
{
T output;
while (this->dequeue(output)) {}
delete _head;
}
void
enqueue(
const T& input)
{
node_t* node = reinterpret_cast<node_t*>(new node_aligned_t);
node->data = input;
node->next = NULL;
std::atomic_thread_fence(std::memory_order_acq_rel);
_head->next = node;
_head = node;
}
bool
dequeue(
T& output)
{
std::atomic_thread_fence(std::memory_order_consume);
if (!_tail->next) {
return false;
}
output = _tail->next->data;
std::atomic_thread_fence(std::memory_order_acq_rel);
_back = _tail;
_tail = _back->next;
delete _back;
return true;
}
private:
struct node_t
{
node_t* next;
T data;
};
typedef typename std::aligned_storage<sizeof(node_t), std::alignment_of<node_t>::value>::type node_aligned_t;
node_t* _head;
char _cache_line[64];
node_t* _tail;
node_t* _back;
spsc_queue_t(const spsc_queue_t&) {}
void operator=(const spsc_queue_t&) {}
};
#endif
================================================
FILE: src/main.cpp
================================================
#include <iostream>
#include <thread>
#include "spsc-queue.hpp"
#include "mpsc-queue.hpp"
#include "spsc-bounded-queue.hpp"
#include "mpmc-bounded-queue.hpp"
#define COUNT 100000000
template<typename T>
void
consumer_func(
T* queue)
{
size_t count = COUNT;
size_t value = 0;
while (count > 0) {
if (queue->dequeue(value)) {
--count;
}
}
}
template<typename T>
void
bounded_producer_func(
T* queue)
{
size_t count = COUNT;
while (count > 0) {
if (queue->enqueue(count)) {
--count;
}
}
}
template<typename T>
void
producer_func(
T* queue)
{
for (int count = 0; count < COUNT; ++count) {
queue->enqueue(count);
}
}
template<typename T>
long double
run_test(
T producer_func,
T consumer_func)
{
typedef std::chrono::high_resolution_clock clock_t;
typedef std::chrono::time_point<clock_t> time_t;
time_t start;
time_t end;
start = clock_t::now();
std::thread producer(producer_func);
std::thread consumer(consumer_func);
producer.join();
consumer.join();
end = clock_t::now();
return
(end - start).count()
* ((double) std::chrono::high_resolution_clock::period::num
/ std::chrono::high_resolution_clock::period::den);
}
int
main()
{
{
typedef spsc_bounded_queue_t<size_t> queue_t;
queue_t queue(65536);
long double seconds = run_test(std::bind(&bounded_producer_func<queue_t>, &queue),
std::bind(&consumer_func<queue_t>, &queue));
std::cout << "SPSC bound queue completed "
<< COUNT
<< " iterations in "
<< seconds
<< " seconds. "
<< ((long double) COUNT / seconds) / 1000000
<< " million enqueue/dequeue pairs per second."
<< std::endl;
}
{
typedef mpmc_bounded_queue_t<size_t> queue_t;
queue_t queue(65536);
long double seconds = run_test(std::bind(&bounded_producer_func<queue_t>, &queue),
std::bind(&consumer_func<queue_t>, &queue));
std::cout << "MPMC bound queue completed "
<< COUNT
<< " iterations in "
<< seconds
<< " seconds. "
<< ((long double) COUNT / seconds) / 1000000
<< " million enqueue/dequeue pairs per second."
<< std::endl;
}
{
typedef spsc_queue_t<size_t> queue_t;
queue_t queue;
long double seconds = run_test(std::bind(&producer_func<queue_t>, &queue),
std::bind(&consumer_func<queue_t>, &queue));
std::cout << "SPSC dynamic queue completed "
<< COUNT
<< " iterations in "
<< seconds
<< " seconds. "
<< ((long double) COUNT / seconds) / 1000000
<< " million enqueue/dequeue pairs per second."
<< std::endl;
}
{
typedef mpsc_queue_t<size_t> queue_t;
queue_t queue;
long double seconds = run_test(std::bind(&producer_func<queue_t>, &queue),
std::bind(&consumer_func<queue_t>, &queue));
std::cout << "MPSC dynamic queue completed "
<< COUNT
<< " iterations in "
<< seconds
<< " seconds. "
<< ((long double) COUNT / seconds) / 1000000
<< " million enqueue/dequeue pairs per second."
<< std::endl;
}
return 0;
}
gitextract_idzpu85s/
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── include/
│ ├── mpmc-bounded-queue.hpp
│ ├── mpsc-queue.hpp
│ ├── spsc-bounded-queue.hpp
│ └── spsc-queue.hpp
└── src/
└── main.cpp
SYMBOL INDEX (28 symbols across 5 files)
FILE: include/mpmc-bounded-queue.hpp
class mpmc_bounded_queue_t (line 37) | class mpmc_bounded_queue_t
method mpmc_bounded_queue_t (line 41) | mpmc_bounded_queue_t(
method enqueue (line 63) | bool
method dequeue (line 104) | bool
type node_t (line 145) | struct node_t
method mpmc_bounded_queue_t (line 164) | mpmc_bounded_queue_t(const mpmc_bounded_queue_t&) {}
FILE: include/mpsc-queue.hpp
class mpsc_queue_t (line 36) | class mpsc_queue_t
method mpsc_queue_t (line 40) | mpsc_queue_t() :
method enqueue (line 56) | void
method dequeue (line 68) | bool
type buffer_node_t (line 88) | struct buffer_node_t
method mpsc_queue_t (line 99) | mpsc_queue_t(const mpsc_queue_t&) {}
FILE: include/spsc-bounded-queue.hpp
class spsc_bounded_queue_t (line 41) | class spsc_bounded_queue_t
method spsc_bounded_queue_t (line 45) | spsc_bounded_queue_t(
method enqueue (line 62) | bool
method dequeue (line 76) | bool
method spsc_bounded_queue_t (line 107) | spsc_bounded_queue_t(const spsc_bounded_queue_t&) {}
FILE: include/spsc-queue.hpp
class spsc_queue_t (line 37) | class spsc_queue_t
method spsc_queue_t (line 41) | spsc_queue_t() :
method enqueue (line 55) | void
method dequeue (line 68) | bool
type node_t (line 89) | struct node_t
method spsc_queue_t (line 102) | spsc_queue_t(const spsc_queue_t&) {}
FILE: src/main.cpp
function consumer_func (line 12) | void
function bounded_producer_func (line 27) | void
function producer_func (line 40) | void
function run_test (line 50) | long double
function main (line 74) | int
Condensed preview — 9 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (25K chars).
[
{
"path": ".gitignore",
"chars": 203,
"preview": "# 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*.l"
},
{
"path": "CMakeLists.txt",
"chars": 1749,
"preview": "CMAKE_MINIMUM_REQUIRED(VERSION 2.8.0)\nset(PROJECT_NAME_STR queue-test)\nproject(${PROJECT_NAME_STR} C CXX)\n\n#------------"
},
{
"path": "LICENSE",
"chars": 1210,
"preview": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, c"
},
{
"path": "README.md",
"chars": 856,
"preview": "Lock Free Queues\n==================\n\nPublic domain implementation of four different lock free queues:\n * SPSC lock free"
},
{
"path": "include/mpmc-bounded-queue.hpp",
"chars": 6358,
"preview": "// This is free and unencumbered software released into the public domain.\n\n// Anyone is free to copy, modify, publish, "
},
{
"path": "include/mpsc-queue.hpp",
"chars": 3320,
"preview": "// This is free and unencumbered software released into the public domain.\n\n// Anyone is free to copy, modify, publish, "
},
{
"path": "include/spsc-bounded-queue.hpp",
"chars": 3455,
"preview": "// This is free and unencumbered software released into the public domain.\n\n// Anyone is free to copy, modify, publish, "
},
{
"path": "include/spsc-queue.hpp",
"chars": 2930,
"preview": "// This is free and unencumbered software released into the public domain.\n\n// Anyone is free to copy, modify, publish, "
},
{
"path": "src/main.cpp",
"chars": 3760,
"preview": "#include <iostream>\n#include <thread>\n\n#include \"spsc-queue.hpp\"\n#include \"mpsc-queue.hpp\"\n#include \"spsc-bounded-queue."
}
]
About this extraction
This page contains the full source code of the mstump/queues GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 9 files (23.3 KB), approximately 5.7k tokens, and a symbol index with 28 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.