summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2017-12-16 09:27:57 +0100
committerDavid Robillard <d@drobilla.net>2017-12-16 09:27:57 +0100
commitae9f2970367b252fd0a285c0126cfbe1affd10ba (patch)
tree466a396780bcc7cc0729568b57c8cae1dcc28046
parent3b18ee6cd6778136180062c0e4cf69e2635da966 (diff)
downloadpatchage-ae9f2970367b252fd0a285c0126cfbe1affd10ba.tar.gz
patchage-ae9f2970367b252fd0a285c0126cfbe1affd10ba.tar.bz2
patchage-ae9f2970367b252fd0a285c0126cfbe1affd10ba.zip
Use modern C++ atomics
-rw-r--r--src/Queue.hpp61
1 files changed, 18 insertions, 43 deletions
diff --git a/src/Queue.hpp b/src/Queue.hpp
index 136de17..ab47aed 100644
--- a/src/Queue.hpp
+++ b/src/Queue.hpp
@@ -1,46 +1,36 @@
/* This file is part of Patchage.
- * Copyright 2007-2014 David Robillard <http://drobilla.net>
+ * Copyright 2007-2017 David Robillard <http://drobilla.net>
*
* Patchage is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
- * Software Foundation, either version 3 of the License, or (at your option)
- * any later version.
+ * Software Foundation, either version 3 of the License, or any later version.
*
* Patchage is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
*
- * You should have received a copy of the GNU General Public License
- * along with Patchage. If not, see <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU General Public License along with
+ * Patchage. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef QUEUE_HPP_INCLUDED
#define QUEUE_HPP_INCLUDED
+#include <atomic>
#include <cassert>
-#ifdef __APPLE__
-# include <libkern/OSAtomic.h>
-#endif
-
-/**
- Realtime-safe single-reader single-writer queue.
-
- This is a RingBuffer but templated for fixed sized objects which makes its
- use a bit more efficient and cleaner in C++ than a traditional byte oriented
- ring buffer.
-*/
+/** Realtime-safe single-reader single-writer queue */
template <typename T>
class Queue
{
public:
/** @param size Size in number of elements */
- explicit Queue(uint32_t size);
+ explicit Queue(size_t size);
~Queue();
// Any thread:
- inline uint32_t capacity() const { return _size - 1; }
+ inline size_t capacity() const { return _size - 1; }
// Write thread(s):
@@ -54,27 +44,14 @@ public:
inline void pop();
private:
- Queue(const Queue&); ///< Undefined (noncopyable)
- Queue& operator=(const Queue&); ///< Undefined (noncopyable)
-
- static inline void barrier() {
-#if defined(__APPLE__)
- OSMemoryBarrier();
-#elif (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
- __sync_synchronize();
-#else
-# warning Memory barriers unsupported, possible bugs on SMP systems
-#endif
- }
-
- int _front; ///< Index to front of queue
- int _back; ///< Index to back of queue (1 past last element)
- const uint32_t _size; ///< Size of _objects (1 more than can be stored)
- T* const _objects; ///< Circular array containing queued elements
+ std::atomic<size_t> _front; ///< Index to front of queue
+ std::atomic<size_t> _back; ///< Index to back of queue (one past end)
+ const size_t _size; ///< Size of `_objects` (at most _size-1)
+ T* const _objects; ///< Fixed array containing queued elements
};
template<typename T>
-Queue<T>::Queue(uint32_t size)
+Queue<T>::Queue(size_t size)
: _front(0)
, _back(0)
, _size(size + 1)
@@ -95,7 +72,7 @@ template <typename T>
inline bool
Queue<T>::empty() const
{
- return (_back == _front);
+ return (_back.load() == _front.load());
}
/** Return whether or not the queue is full.
@@ -104,7 +81,7 @@ template <typename T>
inline bool
Queue<T>::full() const
{
- return (((_front - _back + _size) % _size) == 1);
+ return (((_front.load() - _back.load() + _size) % _size) == 1);
}
/** Return the element at the front of the queue without removing it
@@ -113,7 +90,7 @@ template <typename T>
inline T&
Queue<T>::front() const
{
- return _objects[_front];
+ return _objects[_front.load()];
}
/** Push an item onto the back of the Queue - realtime-safe, not thread-safe.
@@ -128,9 +105,8 @@ Queue<T>::push(const T& elem)
if (full()) {
return false;
} else {
- const int back = _back;
+ unsigned back = _back.load();
_objects[back] = elem;
- barrier();
_back = (back + 1) % _size;
return true;
}
@@ -149,8 +125,7 @@ Queue<T>::pop()
assert(!empty());
assert(_size > 0);
- barrier();
- _front = (_front + 1) % (_size);
+ _front = (_front.load() + 1) % (_size);
}
#endif // QUEUE_HPP_INCLUDED