120 lines
4.2 KiB
C++
120 lines
4.2 KiB
C++
/////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// file: LockLessQueue_SPSC.h //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// description: Template implementation of a thread-safe single //
|
|
// producer, single consumer lock-less queue. //
|
|
// //
|
|
// build number: source //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Copyright (c) 2022 Acroname Inc. - All Rights Reserved //
|
|
// //
|
|
// This file is part of the BrainStem release. See the license.txt //
|
|
// file included with this package or go to //
|
|
// https://acroname.com/software/brainstem-development-kit //
|
|
// for full license details. //
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
#ifndef _LocklessQueue_SPSC_H_
|
|
#define _LocklessQueue_SPSC_H_
|
|
|
|
#if defined(__cplusplus)
|
|
|
|
#include <atomic>
|
|
|
|
namespace Acroname {
|
|
|
|
/// Template class of a thread-safe queue when used as a single producer,
|
|
/// single consumer queue.
|
|
template <class T>
|
|
class LocklessQueue_SPSC {
|
|
public:
|
|
|
|
/// Constructor - Creates a queue with the desired buffer size.
|
|
/// Note: Actually buffer size is always buffer
|
|
/// \param bufferSize - Size of queue to create.
|
|
/// Actual size is always bufferSize - 1 because of internal overhead.
|
|
LocklessQueue_SPSC(uint32_t bufferSize = 256) :
|
|
_buffer(new T[bufferSize]),
|
|
_bufferSize(bufferSize),
|
|
_head(0),
|
|
_tail(0)
|
|
{ }
|
|
|
|
/// Destructor - Recovers internal memory.
|
|
~LocklessQueue_SPSC() {
|
|
delete[] _buffer;
|
|
_buffer = nullptr;
|
|
}
|
|
|
|
/// Pushes data into the queue.
|
|
/// Should only be called by one thread context
|
|
/// \param value Element to be queued.
|
|
/// \return True on success; False if the buffer is full
|
|
bool push(T value);
|
|
|
|
/// Pops data off of the queue
|
|
/// Should only be called by one thread context.
|
|
/// \param value Element to be fill from the queue.
|
|
/// \return True on success; False if the buffer is empty
|
|
bool pop(T* value);
|
|
|
|
/// Queries the number of elements in the queue.
|
|
/// \return Number of element in queue.
|
|
uint16_t size();
|
|
|
|
private:
|
|
T* _buffer;
|
|
const uint16_t _bufferSize;
|
|
std::atomic<uint16_t> _head;
|
|
std::atomic<uint16_t> _tail;
|
|
|
|
inline uint16_t _increment(uint16_t value);
|
|
};
|
|
|
|
|
|
|
|
|
|
template <class T>
|
|
bool LocklessQueue_SPSC<T>::push(T value) {
|
|
uint16_t newHead = _increment(_head);
|
|
if(newHead != _tail) {
|
|
_buffer[newHead] = value;
|
|
_head = newHead;
|
|
return true;
|
|
}
|
|
else { return false; }
|
|
}
|
|
|
|
template <class T>
|
|
bool LocklessQueue_SPSC<T>::pop(T* value) {
|
|
if(_tail != _head) {
|
|
_tail = _increment(_tail);
|
|
*value = _buffer[_tail];
|
|
return true;
|
|
}
|
|
else { return false; }
|
|
}
|
|
|
|
template <class T>
|
|
uint16_t LocklessQueue_SPSC<T>::size() {
|
|
uint16_t head = _head;
|
|
uint16_t tail = _tail;
|
|
if(head >= tail) { return head - tail; }
|
|
else { return (_bufferSize - tail) + head; }
|
|
}
|
|
|
|
template <class T>
|
|
inline uint16_t LocklessQueue_SPSC<T>::_increment(uint16_t value) {
|
|
return (((value + 1) < _bufferSize) ? (value + 1) : (0));
|
|
}
|
|
}
|
|
|
|
#endif//defined(__cplusplus)
|
|
|
|
#endif //_LocklessQueue_SPSC_H_
|