summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/thread/example/shared_mutex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/thread/example/shared_mutex.cpp')
-rw-r--r--src/boost/libs/thread/example/shared_mutex.cpp746
1 files changed, 746 insertions, 0 deletions
diff --git a/src/boost/libs/thread/example/shared_mutex.cpp b/src/boost/libs/thread/example/shared_mutex.cpp
new file mode 100644
index 000000000..c0ef7a522
--- /dev/null
+++ b/src/boost/libs/thread/example/shared_mutex.cpp
@@ -0,0 +1,746 @@
+// Copyright (C) 2012 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
+#define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
+#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
+
+#include <iostream>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/lock_algorithms.hpp>
+#include <boost/thread/thread_only.hpp>
+#include <vector>
+
+#if defined BOOST_THREAD_USES_CHRONO
+#include <boost/chrono/chrono_io.hpp>
+
+
+enum {reading, writing};
+int state = reading;
+
+#if 1
+
+boost::mutex&
+cout_mut()
+{
+ static boost::mutex m;
+ return m;
+}
+
+void
+print(const char* tag, unsigned count, char ch)
+{
+ boost::lock_guard<boost::mutex> _(cout_mut());
+ std::cout << tag << count << ch;
+}
+
+#elif 0
+
+boost::recursive_mutex&
+cout_mut()
+{
+ static boost::recursive_mutex m;
+ return m;
+}
+
+void print() {}
+
+template <class A0, class ...Args>
+void
+print(const A0& a0, const Args& ...args)
+{
+ boost::lock_guard<boost::recursive_mutex> _(cout_mut());
+ std::cout << a0;
+ print(args...);
+}
+
+#else
+
+template <class A0, class A1, class A2>
+void
+print(const A0&, const A1& a1, const A2&)
+{
+ assert(a1 > 10000);
+}
+
+#endif
+
+namespace S
+{
+
+boost::shared_mutex mut;
+
+void reader()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ mut.lock_shared();
+ assert(state == reading);
+ ++count;
+ mut.unlock_shared();
+ }
+ print("reader = ", count, '\n');
+}
+
+void writer()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ mut.lock();
+ state = writing;
+ assert(state == writing);
+ state = reading;
+ ++count;
+ mut.unlock();
+ }
+ print("writer = ", count, '\n');
+}
+
+void try_reader()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_shared())
+ {
+ assert(state == reading);
+ ++count;
+ mut.unlock_shared();
+ }
+ }
+ print("try_reader = ", count, '\n');
+}
+
+void try_writer()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock())
+ {
+ state = writing;
+ assert(state == writing);
+ state = reading;
+ ++count;
+ mut.unlock();
+ }
+ }
+ print("try_writer = ", count, '\n');
+}
+
+void try_for_reader()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
+ {
+ assert(state == reading);
+ ++count;
+ mut.unlock_shared();
+ }
+ }
+ print("try_for_reader = ", count, '\n');
+}
+
+void try_for_writer()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_for(boost::chrono::microseconds(5)))
+ {
+ state = writing;
+ assert(state == writing);
+ state = reading;
+ ++count;
+ mut.unlock();
+ }
+ }
+ print("try_for_writer = ", count, '\n');
+}
+
+void
+test_shared_mutex()
+{
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ {
+ boost::thread t1(reader);
+ boost::thread t2(writer);
+ boost::thread t3(reader);
+ t1.join();
+ t2.join();
+ t3.join();
+ }
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ {
+ boost::thread t1(try_reader);
+ boost::thread t2(try_writer);
+ boost::thread t3(try_reader);
+ t1.join();
+ t2.join();
+ t3.join();
+ }
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ {
+ boost::thread t1(try_for_reader);
+ boost::thread t2(try_for_writer);
+ boost::thread t3(try_for_reader);
+ t1.join();
+ t2.join();
+ t3.join();
+ }
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+}
+
+}
+
+namespace U
+{
+
+boost::upgrade_mutex mut;
+
+void reader()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ mut.lock_shared();
+ assert(state == reading);
+ ++count;
+ mut.unlock_shared();
+ }
+ print("reader = ", count, '\n');
+}
+
+void writer()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ mut.lock();
+ state = writing;
+ assert(state == writing);
+ state = reading;
+ ++count;
+ mut.unlock();
+ }
+ print("writer = ", count, '\n');
+}
+
+void try_reader()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_shared())
+ {
+ assert(state == reading);
+ ++count;
+ mut.unlock_shared();
+ }
+ }
+ print("try_reader = ", count, '\n');
+}
+
+void try_writer()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock())
+ {
+ state = writing;
+ assert(state == writing);
+ state = reading;
+ ++count;
+ mut.unlock();
+ }
+ }
+ print("try_writer = ", count, '\n');
+}
+
+void try_for_reader()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
+ {
+ assert(state == reading);
+ ++count;
+ mut.unlock_shared();
+ }
+ }
+ print("try_for_reader = ", count, '\n');
+}
+
+void try_for_writer()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_for(boost::chrono::microseconds(5)))
+ {
+ state = writing;
+ assert(state == writing);
+ state = reading;
+ ++count;
+ mut.unlock();
+ }
+ }
+ print("try_for_writer = ", count, '\n');
+}
+
+void upgradable()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ mut.lock_upgrade();
+ assert(state == reading);
+ ++count;
+ mut.unlock_upgrade();
+ }
+ print("upgradable = ", count, '\n');
+}
+
+void try_upgradable()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_upgrade())
+ {
+ assert(state == reading);
+ ++count;
+ mut.unlock_upgrade();
+ }
+ }
+ print("try_upgradable = ", count, '\n');
+}
+
+void try_for_upgradable()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_upgrade_for(boost::chrono::microseconds(5)))
+ {
+ assert(state == reading);
+ ++count;
+ mut.unlock_upgrade();
+ }
+ }
+ print("try_for_upgradable = ", count, '\n');
+}
+
+void clockwise()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ mut.lock_shared();
+ assert(state == reading);
+ if (mut.try_unlock_shared_and_lock())
+ {
+ state = writing;
+ }
+ else if (mut.try_unlock_shared_and_lock_upgrade())
+ {
+ assert(state == reading);
+ mut.unlock_upgrade_and_lock();
+ state = writing;
+ }
+ else
+ {
+ mut.unlock_shared();
+ continue;
+ }
+ assert(state == writing);
+ state = reading;
+ mut.unlock_and_lock_upgrade();
+ assert(state == reading);
+ mut.unlock_upgrade_and_lock_shared();
+ assert(state == reading);
+ mut.unlock_shared();
+ ++count;
+ }
+ print("clockwise = ", count, '\n');
+}
+
+void counter_clockwise()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ mut.lock_upgrade();
+ assert(state == reading);
+ mut.unlock_upgrade_and_lock();
+ assert(state == reading);
+ state = writing;
+ assert(state == writing);
+ state = reading;
+ mut.unlock_and_lock_shared();
+ assert(state == reading);
+ mut.unlock_shared();
+ ++count;
+ }
+ print("counter_clockwise = ", count, '\n');
+}
+
+void try_clockwise()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_shared())
+ {
+ assert(state == reading);
+ if (mut.try_unlock_shared_and_lock())
+ {
+ state = writing;
+ }
+ else if (mut.try_unlock_shared_and_lock_upgrade())
+ {
+ assert(state == reading);
+ mut.unlock_upgrade_and_lock();
+ state = writing;
+ }
+ else
+ {
+ mut.unlock_shared();
+ continue;
+ }
+ assert(state == writing);
+ state = reading;
+ mut.unlock_and_lock_upgrade();
+ assert(state == reading);
+ mut.unlock_upgrade_and_lock_shared();
+ assert(state == reading);
+ mut.unlock_shared();
+ ++count;
+ }
+ }
+ print("try_clockwise = ", count, '\n');
+}
+
+void try_for_clockwise()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
+ {
+ assert(state == reading);
+ if (mut.try_unlock_shared_and_lock_for(boost::chrono::microseconds(5)))
+ {
+ state = writing;
+ }
+ else if (mut.try_unlock_shared_and_lock_upgrade_for(boost::chrono::microseconds(5)))
+ {
+ assert(state == reading);
+ mut.unlock_upgrade_and_lock();
+ state = writing;
+ }
+ else
+ {
+ mut.unlock_shared();
+ continue;
+ }
+ assert(state == writing);
+ state = reading;
+ mut.unlock_and_lock_upgrade();
+ assert(state == reading);
+ mut.unlock_upgrade_and_lock_shared();
+ assert(state == reading);
+ mut.unlock_shared();
+ ++count;
+ }
+ }
+ print("try_for_clockwise = ", count, '\n');
+}
+
+void try_counter_clockwise()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_upgrade())
+ {
+ assert(state == reading);
+ if (mut.try_unlock_upgrade_and_lock())
+ {
+ assert(state == reading);
+ state = writing;
+ assert(state == writing);
+ state = reading;
+ mut.unlock_and_lock_shared();
+ assert(state == reading);
+ mut.unlock_shared();
+ ++count;
+ }
+ else
+ {
+ mut.unlock_upgrade();
+ }
+ }
+ }
+ print("try_counter_clockwise = ", count, '\n');
+}
+
+void try_for_counter_clockwise()
+{
+ typedef boost::chrono::steady_clock Clock;
+ unsigned count = 0;
+ Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
+ while (Clock::now() < until)
+ {
+ if (mut.try_lock_upgrade_for(boost::chrono::microseconds(5)))
+ {
+ assert(state == reading);
+ if (mut.try_unlock_upgrade_and_lock_for(boost::chrono::microseconds(5)))
+ {
+ assert(state == reading);
+ state = writing;
+ assert(state == writing);
+ state = reading;
+ mut.unlock_and_lock_shared();
+ assert(state == reading);
+ mut.unlock_shared();
+ ++count;
+ }
+ else
+ {
+ mut.unlock_upgrade();
+ }
+ }
+ }
+ print("try_for_counter_clockwise = ", count, '\n');
+}
+
+void
+test_upgrade_mutex()
+{
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ {
+ boost::thread t1(reader);
+ boost::thread t2(writer);
+ boost::thread t3(reader);
+ t1.join();
+ t2.join();
+ t3.join();
+ }
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ {
+ boost::thread t1(try_reader);
+ boost::thread t2(try_writer);
+ boost::thread t3(try_reader);
+ t1.join();
+ t2.join();
+ t3.join();
+ }
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ {
+ boost::thread t1(try_for_reader);
+ boost::thread t2(try_for_writer);
+ boost::thread t3(try_for_reader);
+ t1.join();
+ t2.join();
+ t3.join();
+ }
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ {
+ boost::thread t1(reader);
+ boost::thread t2(writer);
+ boost::thread t3(upgradable);
+ t1.join();
+ t2.join();
+ t3.join();
+ }
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ {
+ boost::thread t1(reader);
+ boost::thread t2(writer);
+ boost::thread t3(try_upgradable);
+ t1.join();
+ t2.join();
+ t3.join();
+ }
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ {
+ boost::thread t1(reader);
+ boost::thread t2(writer);
+ boost::thread t3(try_for_upgradable);
+ t1.join();
+ t2.join();
+ t3.join();
+ }
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ {
+ state = reading;
+ boost::thread t1(clockwise);
+ boost::thread t2(counter_clockwise);
+ boost::thread t3(clockwise);
+ boost::thread t4(counter_clockwise);
+ t1.join();
+ t2.join();
+ t3.join();
+ t4.join();
+ }
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ {
+ state = reading;
+ boost::thread t1(try_clockwise);
+ boost::thread t2(try_counter_clockwise);
+ t1.join();
+ t2.join();
+ }
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+// {
+// state = reading;
+// boost::thread t1(try_for_clockwise);
+// boost::thread t2(try_for_counter_clockwise);
+// t1.join();
+// t2.join();
+// }
+// std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+}
+
+}
+
+namespace Assignment
+{
+
+class A
+{
+ typedef boost::upgrade_mutex mutex_type;
+ typedef boost::shared_lock<mutex_type> SharedLock;
+ typedef boost::upgrade_lock<mutex_type> UpgradeLock;
+ typedef boost::unique_lock<mutex_type> Lock;
+
+ mutable mutex_type mut_;
+ std::vector<double> data_;
+
+public:
+
+ A(const A& a)
+ {
+ SharedLock _(a.mut_);
+ data_ = a.data_;
+ }
+
+ A& operator=(const A& a)
+ {
+ if (this != &a)
+ {
+ Lock this_lock(mut_, boost::defer_lock);
+ SharedLock that_lock(a.mut_, boost::defer_lock);
+ boost::lock(this_lock, that_lock);
+ data_ = a.data_;
+ }
+ return *this;
+ }
+
+ void swap(A& a)
+ {
+ Lock this_lock(mut_, boost::defer_lock);
+ Lock that_lock(a.mut_, boost::defer_lock);
+ boost::lock(this_lock, that_lock);
+ data_.swap(a.data_);
+ }
+
+ void average(A& a)
+ {
+ assert(data_.size() == a.data_.size());
+ assert(this != &a);
+
+ Lock this_lock(mut_, boost::defer_lock);
+ UpgradeLock share_that_lock(a.mut_, boost::defer_lock);
+ boost::lock(this_lock, share_that_lock);
+
+ for (unsigned i = 0; i < data_.size(); ++i)
+ data_[i] = (data_[i] + a.data_[i]) / 2;
+
+ SharedLock share_this_lock(boost::move(this_lock));
+ Lock that_lock(boost::move(share_that_lock));
+ a.data_ = data_;
+ }
+};
+
+} // Assignment
+
+void temp()
+{
+ using namespace boost;
+ static upgrade_mutex mut;
+ unique_lock<upgrade_mutex> ul(mut);
+ shared_lock<upgrade_mutex> sl;
+ sl = BOOST_THREAD_MAKE_RV_REF(shared_lock<upgrade_mutex>(boost::move(ul)));
+}
+
+int main()
+{
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ typedef boost::chrono::high_resolution_clock Clock;
+ typedef boost::chrono::duration<double> sec;
+ Clock::time_point t0 = Clock::now();
+
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ S::test_shared_mutex();
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ U::test_upgrade_mutex();
+ std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
+ Clock::time_point t1 = Clock::now();
+ std::cout << sec(t1 - t0) << '\n';
+ return 0;
+}
+
+#else
+#error "This platform doesn't support Boost.Chrono"
+#endif