diff --git a/src/util/double_buffer.hpp b/src/util/double_buffer.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..34dceb7f834768dd4fe768fee03f2ca83f24a7aa
--- /dev/null
+++ b/src/util/double_buffer.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <array>
+#include <atomic>
+
+#include <util/debug.hpp>
+
+namespace nest {
+namespace mc {
+namespace util {
+
+template <typename T>
+class double_buffer {
+private:
+    std::atomic<int> index_;
+    std::array<T, 2> buffers_;
+
+    int other_index() {
+        return index_ ? 0 : 1;
+    }
+
+public:
+    using value_type = T;
+
+    double_buffer() :
+        index_(0)
+    {}
+
+    double_buffer(double_buffer&&) = delete;
+    double_buffer(const double_buffer&) = delete;
+    double_buffer& operator=(const double_buffer&) = delete;
+    double_buffer& operator=(double_buffer&&) = delete;
+
+    void exchange() {
+        index_ ^= 1;
+    }
+
+    value_type& get() {
+        return buffers_[index_];
+    }
+
+    const value_type& get() const {
+        return buffers_[index_];
+    }
+
+    value_type& other() {
+        return buffers_[other_index()];
+    }
+
+    const value_type& other() const {
+        return buffers_[other_index()];
+    }
+};
+
+} // namespace util
+} // namespace mc
+} // namespace nest
diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt
index a3a2d55333f6316b133bff3982ec58e1b03d525d..81976dd21ece69e5a7a520cf941c1fb1fe28022a 100644
--- a/tests/unit/CMakeLists.txt
+++ b/tests/unit/CMakeLists.txt
@@ -11,6 +11,7 @@ set(HEADERS
 set(TEST_SOURCES
     # unit tests
     test_algorithms.cpp
+    test_double_buffer.cpp
     test_cell.cpp
     test_compartments.cpp
     test_event_queue.cpp
diff --git a/tests/unit/test_double_buffer.cpp b/tests/unit/test_double_buffer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1689cc2faac17331694c78830c22cd1ea57777fe
--- /dev/null
+++ b/tests/unit/test_double_buffer.cpp
@@ -0,0 +1,58 @@
+#include "gtest.h"
+
+#include <util/double_buffer.hpp>
+
+// not much to test here: just test that values passed into the constructor
+// are correctly stored in members
+TEST(double_buffer, exchange_and_get)
+{
+    using namespace nest::mc::util;
+
+    double_buffer<int> buf;
+
+    buf.get() = 2134;
+    buf.exchange();
+    buf.get() = 8990;
+    buf.exchange();
+
+    EXPECT_EQ(buf.get(), 2134);
+    EXPECT_EQ(buf.other(), 8990);
+    buf.exchange();
+    EXPECT_EQ(buf.get(), 8990);
+    EXPECT_EQ(buf.other(), 2134);
+    buf.exchange();
+    EXPECT_EQ(buf.get(), 2134);
+    EXPECT_EQ(buf.other(), 8990);
+}
+
+TEST(double_buffer, assign_get_other)
+{
+    using namespace nest::mc::util;
+
+    double_buffer<std::string> buf;
+
+    buf.get()   = "1";
+    buf.other() = "2";
+
+    EXPECT_EQ(buf.get(), "1");
+    EXPECT_EQ(buf.other(), "2");
+}
+
+TEST(double_buffer, non_pod)
+{
+    using namespace nest::mc::util;
+
+    double_buffer<std::string> buf;
+
+    buf.get()   = "1";
+    buf.other() = "2";
+
+    EXPECT_EQ(buf.get(), "1");
+    EXPECT_EQ(buf.other(), "2");
+    buf.exchange();
+    EXPECT_EQ(buf.get(), "2");
+    EXPECT_EQ(buf.other(), "1");
+    buf.exchange();
+    EXPECT_EQ(buf.get(), "1");
+    EXPECT_EQ(buf.other(), "2");
+}