diff options
Diffstat (limited to 'src/boost/libs/thread/example/shared_mutex.cpp')
-rw-r--r-- | src/boost/libs/thread/example/shared_mutex.cpp | 746 |
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 |