summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2013-01-11 03:35:17 +0000
committerDavid Robillard <d@drobilla.net>2013-01-11 03:35:17 +0000
commitf8aa3ee7621758b35ba52a5b17972fa4144710ae (patch)
tree2bf934c558b5c97f858be03101fa1544ecf6835d
parent77d36f84343baa0864e742834be15c0296dc4389 (diff)
downloadraul-f8aa3ee7621758b35ba52a5b17972fa4144710ae.tar.gz
raul-f8aa3ee7621758b35ba52a5b17972fa4144710ae.tar.bz2
raul-f8aa3ee7621758b35ba52a5b17972fa4144710ae.zip
Use C++11 atomics.
git-svn-id: http://svn.drobilla.net/lad/trunk/raul@4916 a436a847-0d15-0410-975c-d299462d15a1
-rw-r--r--raul/AtomicInt.hpp96
-rw-r--r--raul/AtomicPtr.hpp64
-rw-r--r--raul/DoubleBuffer.hpp9
-rw-r--r--raul/Maid.hpp17
-rw-r--r--raul/SRMWQueue.hpp40
-rw-r--r--raul/SRSWQueue.hpp18
-rw-r--r--test/atomic_test.cpp76
-rw-r--r--test/queue_test.cpp8
-rw-r--r--test/thread_test.cpp4
-rw-r--r--wscript2
10 files changed, 48 insertions, 286 deletions
diff --git a/raul/AtomicInt.hpp b/raul/AtomicInt.hpp
deleted file mode 100644
index 172af6b..0000000
--- a/raul/AtomicInt.hpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- This file is part of Raul.
- Copyright 2007-2012 David Robillard <http://drobilla.net>
-
- Raul 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 any later version.
-
- Raul 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 more details.
-
- You should have received a copy of the GNU General Public License
- along with Raul. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef RAUL_ATOMIC_INT_HPP
-#define RAUL_ATOMIC_INT_HPP
-
-#include "raul/barrier.hpp"
-
-namespace Raul {
-
-/** Atomic integer.
- * \ingroup raul
- */
-class AtomicInt {
-public:
- inline AtomicInt(int val) : _val(val) {}
-
- inline AtomicInt(const AtomicInt& copy) : _val(copy.get()) {}
-
- inline int get() const {
- Raul::barrier();
- return _val;
- }
-
- inline void operator=(int val) {
- _val = val;
- Raul::barrier();
- }
-
- inline void operator=(const AtomicInt& val) {
- _val = val.get();
- Raul::barrier();
- }
-
- inline AtomicInt& operator++() { return operator+=(1); }
- inline AtomicInt& operator--() { return operator-=(1); }
- inline bool operator==(int val) const { return get() == val; }
- inline int operator+(int val) const { return get() + val; }
- inline int operator-(int val) const { return get() - val; }
-
- inline bool operator==(const AtomicInt& other) const {
- Raul::barrier();
- return _val == other._val;
- }
-
- inline AtomicInt& operator+=(int val) {
- __sync_fetch_and_add(&_val, val);
- return *this;
- }
-
- inline AtomicInt& operator-=(int val) {
- __sync_fetch_and_sub(&_val, val);
- return *this;
- }
-
- /** Set value to @a val iff current value is @a old.
- * @return true iff set succeeded.
- */
- inline bool compare_and_exchange(int old, int val) {
- return __sync_bool_compare_and_swap(&_val, old, val);
- }
-
- /** Add val to value.
- * @return value immediately before addition took place.
- */
- inline int exchange_and_add(int val) {
- return __sync_fetch_and_add(&_val, val);
- }
-
- /** Decrement value.
- * @return true if value is now 0, otherwise false.
- */
- inline bool decrement_and_test() {
- return __sync_sub_and_fetch(&_val, 1) == 0;
- }
-
-private:
- int _val;
-};
-
-} // namespace Raul
-
-#endif // RAUL_ATOMIC_INT_HPP
diff --git a/raul/AtomicPtr.hpp b/raul/AtomicPtr.hpp
deleted file mode 100644
index 0dc369b..0000000
--- a/raul/AtomicPtr.hpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- This file is part of Raul.
- Copyright 2007-2012 David Robillard <http://drobilla.net>
-
- Raul 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 any later version.
-
- Raul 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 more details.
-
- You should have received a copy of the GNU General Public License
- along with Raul. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef RAUL_ATOMIC_PTR_HPP
-#define RAUL_ATOMIC_PTR_HPP
-
-#include <cstddef>
-
-#include "raul/barrier.hpp"
-
-namespace Raul {
-
-/** Atomic pointer.
- * \ingroup raul
- */
-template<typename T>
-class AtomicPtr {
-public:
- inline AtomicPtr() : _val(NULL) {}
-
- inline AtomicPtr(const AtomicPtr& copy) : _val(copy.get()) {}
-
- inline T* get() const {
- Raul::barrier();
- return static_cast<T*>(_val);
- }
-
- inline bool operator==(const AtomicPtr& other) const {
- Raul::barrier();
- return _val == other._val;
- }
-
- inline void operator=(T* val) {
- _val = val;
- Raul::barrier();
- }
-
- /** Set value to @a val iff current value is @a old.
- * @return true iff set succeeded.
- */
- inline bool compare_and_exchange(void* old, void* val) {
- return __sync_bool_compare_and_swap(&_val, old, val);
- }
-
-private:
- void* _val;
-};
-
-} // namespace Raul
-
-#endif // RAUL_ATOMIC_PTR_HPP
diff --git a/raul/DoubleBuffer.hpp b/raul/DoubleBuffer.hpp
index 28080d6..092d529 100644
--- a/raul/DoubleBuffer.hpp
+++ b/raul/DoubleBuffer.hpp
@@ -17,8 +17,7 @@
#ifndef RAUL_DOUBLE_BUFFER_HPP
#define RAUL_DOUBLE_BUFFER_HPP
-#include "raul/AtomicInt.hpp"
-#include "raul/AtomicPtr.hpp"
+#include <atomic>
namespace Raul {
@@ -88,9 +87,9 @@ private:
RAUL_DB_LOCK_READ
};
- AtomicInt _state;
- AtomicPtr<T> _read_val;
- T _vals[2];
+ std::atomic<States> _state;
+ std::atomic<T*> _read_val;
+ T _vals[2];
};
} // namespace Raul
diff --git a/raul/Maid.hpp b/raul/Maid.hpp
index f7870ec..337d7f9 100644
--- a/raul/Maid.hpp
+++ b/raul/Maid.hpp
@@ -17,7 +17,8 @@
#ifndef RAUL_MAID_HPP
#define RAUL_MAID_HPP
-#include "raul/AtomicPtr.hpp"
+#include <atomic>
+
#include "raul/Disposable.hpp"
#include "raul/Manageable.hpp"
#include "raul/Noncopyable.hpp"
@@ -50,8 +51,8 @@ public:
inline void dispose(Disposable* obj) {
if (obj) {
while (true) {
- obj->_maid_next = _disposed.get();
- if (_disposed.compare_and_exchange(obj->_maid_next, obj)) {
+ obj->_maid_next = _disposed.load();
+ if (_disposed.compare_exchange_strong(obj->_maid_next, obj)) {
return;
}
}
@@ -83,14 +84,14 @@ public:
// Atomically get the head of the disposed list
Disposable* disposed;
while (true) {
- disposed = _disposed.get();
- if (_disposed.compare_and_exchange(disposed, NULL)) {
+ disposed = _disposed.load();
+ if (_disposed.compare_exchange_strong(disposed, NULL)) {
break;
}
}
// Free the disposed list
- for (Disposable* obj = _disposed.get(); obj;) {
+ for (Disposable* obj = _disposed.load(); obj;) {
Disposable* const next = obj->_maid_next;
delete obj;
obj = next;
@@ -107,8 +108,8 @@ public:
}
private:
- AtomicPtr<Disposable> _disposed;
- SharedPtr<Manageable> _managed;
+ std::atomic<Disposable*> _disposed;
+ SharedPtr<Manageable> _managed;
};
} // namespace Raul
diff --git a/raul/SRMWQueue.hpp b/raul/SRMWQueue.hpp
index ac790ea..12b4b19 100644
--- a/raul/SRMWQueue.hpp
+++ b/raul/SRMWQueue.hpp
@@ -21,7 +21,6 @@
#include <cstdlib>
#include <cmath>
-#include "raul/AtomicInt.hpp"
#include "raul/Noncopyable.hpp"
namespace Raul {
@@ -71,16 +70,15 @@ public:
private:
- // Note that _front doesn't need to be an AtomicInt since it's only accessed
- // by the (single) reader thread
+ // Note that _front needn't be atomic since it's only used by reader
- unsigned _front; ///< Circular index of element at front of queue (READER ONLY)
- AtomicInt _back; ///< Circular index 1 past element at back of queue (WRITERS ONLY)
- AtomicInt _write_space; ///< Remaining free space for new elements (all threads)
- const unsigned _size; ///< Size of @ref _objects (you can store _size-1 objects)
+ unsigned _front; ///< Circular index of element at front of queue (READER ONLY)
+ std::atomic<int> _back; ///< Circular index 1 past element at back of queue (WRITERS ONLY)
+ std::atomic<int> _write_space; ///< Remaining free space for new elements (all threads)
+ const unsigned _size; ///< Size of @ref _objects (you can store _size-1 objects)
- T* const _objects; ///< Fixed array containing queued elements
- AtomicInt* const _valid; ///< Parallel array to _objects, whether loc is written or not
+ T* const _objects; ///< Fixed array containing queued elements
+ std::atomic<bool>* const _valid; ///< Parallel array to _objects, whether loc is written or not
};
template<typename T>
@@ -90,20 +88,21 @@ SRMWQueue<T>::SRMWQueue(size_t size)
, _write_space(size)
, _size(size+1)
, _objects((T*)calloc(_size, sizeof(T)))
- , _valid((AtomicInt*)calloc(_size, sizeof(AtomicInt)))
+ , _valid(new std::atomic<bool>[_size])
{
assert(log2(size) - (int)log2(size) == 0);
assert(size > 1);
- assert(_size-1 == (unsigned)_write_space.get());
+ assert(_size-1 == (unsigned)_write_space.load());
for (unsigned i = 0; i < _size; ++i) {
- assert(_valid[i].get() == 0);
+ assert(!_valid[i]);
}
}
template <typename T>
SRMWQueue<T>::~SRMWQueue()
{
+ delete _valid;
free(_objects);
}
@@ -115,7 +114,7 @@ template <typename T>
inline bool
SRMWQueue<T>::full() const
{
- return (_write_space.get() <= 0);
+ return (_write_space.load() <= 0);
}
/** Push an item onto the back of the SRMWQueue - realtime-safe, not thread-safe.
@@ -129,7 +128,7 @@ template <typename T>
inline bool
SRMWQueue<T>::push(const T& elem)
{
- const int old_write_space = _write_space.exchange_and_add(-1);
+ const int old_write_space = _write_space--;
const bool already_full = (old_write_space <= 0);
/* Technically right here pop could be called in the reader thread and
@@ -146,11 +145,11 @@ SRMWQueue<T>::push(const T& elem)
} else {
// Note: _size must be a power of 2 for this to not explode when _back overflows
- const unsigned write_index = (unsigned)_back.exchange_and_add(1) % _size;
+ const unsigned write_index = _back++ % _size;
- assert(_valid[write_index] == 0);
+ assert(!_valid[write_index]);
_objects[write_index] = elem;
- ++(_valid[write_index]);
+ _valid[write_index] = true;
return true;
}
@@ -164,7 +163,7 @@ template <typename T>
inline bool
SRMWQueue<T>::empty() const
{
- return (_valid[_front].get() == 0);
+ return (!_valid[_front].load());
}
/** Return the element at the front of the queue without removing it.
@@ -190,12 +189,11 @@ template <typename T>
inline void
SRMWQueue<T>::pop()
{
- assert(_valid[_front] == 1);
- --(_valid[_front]);
+ _valid[_front] = false;
_front = (_front + 1) % (_size);
- if (_write_space.get() < 0)
+ if (_write_space.load() < 0)
_write_space = 1;
else
++_write_space;
diff --git a/raul/SRSWQueue.hpp b/raul/SRSWQueue.hpp
index 409497b..b9554a6 100644
--- a/raul/SRSWQueue.hpp
+++ b/raul/SRSWQueue.hpp
@@ -17,9 +17,9 @@
#ifndef RAUL_SRSW_QUEUE_HPP
#define RAUL_SRSW_QUEUE_HPP
+#include <atomic>
#include <cassert>
-#include "raul/AtomicInt.hpp"
#include "raul/Noncopyable.hpp"
namespace Raul {
@@ -60,9 +60,9 @@ public:
inline void pop();
private:
- AtomicInt _front; ///< Index to front of queue (circular)
- AtomicInt _back; ///< Index to back of queue (one past last element) (circular)
- const size_t _size; ///< Size of @ref _objects (you can store _size-1 objects)
+ std::atomic<size_t> _front; ///< Index to front of queue (circular)
+ std::atomic<size_t> _back; ///< Index to back of queue (one past last element) (circular)
+ const size_t _size; ///< Size of @ref _objects (you can store _size-1 objects)
T* const _objects; ///< Fixed array containing queued elements
};
@@ -88,7 +88,7 @@ template <typename T>
inline bool
SRSWQueue<T>::empty() const
{
- return (_back.get() == _front.get());
+ return (_back.load() == _front.load());
}
/** Return whether or not the queue is full.
@@ -97,7 +97,7 @@ template <typename T>
inline bool
SRSWQueue<T>::full() const
{
- return (((_front.get() - _back.get() + _size) % _size) == 1);
+ return (((_front.load() - _back.load() + _size) % _size) == 1);
}
/** Return the element at the front of the queue without removing it
@@ -106,7 +106,7 @@ template <typename T>
inline T&
SRSWQueue<T>::front() const
{
- return _objects[_front.get()];
+ return _objects[_front.load()];
}
/** Push an item onto the back of the SRSWQueue - realtime-safe, not thread-safe.
@@ -121,7 +121,7 @@ SRSWQueue<T>::push(const T& elem)
if (full()) {
return false;
} else {
- unsigned back = _back.get();
+ unsigned back = _back.load();
_objects[back] = elem;
_back = (back + 1) % _size;
return true;
@@ -141,7 +141,7 @@ SRSWQueue<T>::pop()
assert(!empty());
assert(_size > 0);
- _front = (_front.get() + 1) % (_size);
+ _front = (_front.load() + 1) % (_size);
}
} // namespace Raul
diff --git a/test/atomic_test.cpp b/test/atomic_test.cpp
deleted file mode 100644
index 5b6260c..0000000
--- a/test/atomic_test.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- This file is part of Raul.
- Copyright 2007-2012 David Robillard <http://drobilla.net>
-
- Raul 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 any later version.
-
- Raul 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 more details.
-
- You should have received a copy of the GNU General Public License
- along with Raul. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "raul/AtomicInt.hpp"
-#include "raul/AtomicPtr.hpp"
-
-using namespace std;
-using namespace Raul;
-
-#define TEST(cond) { if (!(cond)) return 1; }
-
-int
-main()
-{
- /* TODO: Actually test functionality... */
- AtomicInt i(0);
- TEST(i == 0);
-
- AtomicInt j(i);
- TEST(i == j);
-
- ++i;
- TEST(i == 1);
-
- --i;
- TEST(i == 0);
-
- TEST(i + 1 == 1);
- TEST(i - 1 == -1);
-
- i += 2;
- TEST(i == 2);
-
- i -= 4;
- TEST(i == -2);
-
- TEST(i.compare_and_exchange(-2, 0));
- TEST(i == 0);
-
- TEST(i.exchange_and_add(5) == 0);
- TEST(i == 5);
-
- i = 1;
- TEST(i == 1);
- TEST(i.decrement_and_test());
-
- int five = 5;
- int seven = 7;
- AtomicPtr<int> p;
- TEST(p.get() == NULL);
-
- AtomicPtr<int> q(p);
- TEST(p == q);
-
- p = &five;
- TEST(p.get() == &five);
- TEST(*p.get() == 5);
- TEST(p.compare_and_exchange(&five, &seven));
- TEST(p.get() == &seven);
- TEST(*p.get() = 7);
-
- return 0;
-}
diff --git a/test/queue_test.cpp b/test/queue_test.cpp
index bcdf039..b13c13f 100644
--- a/test/queue_test.cpp
+++ b/test/queue_test.cpp
@@ -19,11 +19,11 @@
#include <stdlib.h>
#include <algorithm>
+#include <atomic>
#include <iostream>
#include <string>
#include <vector>
-#include "raul/AtomicInt.hpp"
#include "raul/SRMWQueue.hpp"
#include "raul/SRSWQueue.hpp"
#include "raul/Thread.hpp"
@@ -41,8 +41,8 @@ static const unsigned PUSHES_PER_ITERATION = 3;
struct Record {
Record() : read_count(0), write_count(0) {}
- AtomicInt read_count;
- AtomicInt write_count;
+ std::atomic<int> read_count;
+ std::atomic<int> write_count;
};
Record data[NUM_DATA];
@@ -90,7 +90,7 @@ data_is_sane()
{
unsigned ret = 0;
for (unsigned i = 0; i < NUM_DATA; ++i) {
- unsigned diff = abs(data[i].read_count.get() - data[i].write_count.get());
+ unsigned diff = abs(data[i].read_count.load() - data[i].write_count.load());
ret += diff;
}
diff --git a/test/thread_test.cpp b/test/thread_test.cpp
index f823936..f59894f 100644
--- a/test/thread_test.cpp
+++ b/test/thread_test.cpp
@@ -14,9 +14,9 @@
along with Raul. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <atomic>
#include <iostream>
-#include "raul/AtomicInt.hpp"
#include "raul/Semaphore.hpp"
#include "raul/Thread.hpp"
#include "raul/ThreadVar.hpp"
@@ -25,7 +25,7 @@ using namespace std;
using namespace Raul;
Raul::ThreadVar<int> var(0);
-Raul::AtomicInt n_errors(0);
+std::atomic<int> n_errors(0);
class Waiter : public Raul::Thread {
public:
diff --git a/wscript b/wscript
index 495813a..a26c041 100644
--- a/wscript
+++ b/wscript
@@ -43,6 +43,7 @@ def options(opt):
def configure(conf):
conf.load('compiler_cxx')
autowaf.configure(conf)
+ conf.env.append_unique('CXXFLAGS', ['-std=c++11'])
conf.line_just = 40
autowaf.display_header('Raul Configuration')
@@ -76,7 +77,6 @@ def configure(conf):
tests = '''
test/atom_test
- test/atomic_test
test/double_buffer_test
test/path_test
test/ptr_test