#include <memory>
#include <atomic>
-
+#include <mutex>
/** This is sort of a light-weight RCU idea.
Suitable for when you frequently consult some "readonly" state, which infrequently
gets changed. One way of dealing with this is fully locking access to the state, but
//! Safely & slowly modify the global state
template<typename F>
void modify(F act) {
- std::lock_guard<std::mutex> l(d_lock);
- act(*d_state);
+ std::lock_guard<std::mutex> l(d_lock);
+ auto state=*d_state; // and yes, these three steps are necessary, can't ever modify state in place, even when locked!
+ act(state);
+ d_state = std::make_shared<T>(T(state));
++d_generation;
}
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#include <boost/test/unit_test.hpp>
+#include "sholder.hh"
+#include <thread>
+
+using std::string;
+
+struct TestObject
+{
+ string name;
+ uint64_t number;
+};
+
+static GlobalStateHolder<TestObject> g_to;
+std::atomic<bool> g_failed;
+
+BOOST_AUTO_TEST_SUITE(sholder_hh)
+
+void treader()
+{
+ auto local = g_to.getLocal();
+ for(int n=0; n < 10000000; ++n) {
+ auto g = *local;
+ if(g.name != std::to_string(g.number)) {
+ g_failed=1;
+ break;
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_sholder) {
+ g_to.setState({"1", 1});
+
+ std::thread t1(treader);
+ for(unsigned int n=0; n < 1000000; ++n) {
+ g_to.setState({std::to_string(n), n});
+ g_to.modify([n](TestObject& to) { to.number = 2*n; to.name=std::to_string(to.number);} );
+ }
+ t1.join();
+ BOOST_CHECK_EQUAL(g_failed, 0);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+