codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
#pragma once #define __STDC_LIMIT_MACROS #include <iostream> #include <array> #include <mutex> #include <memory> #include <functional> #include <algorithm> #include <thread> #include <condition_variable> namespace syncope { class pool_guard_base {}; typedef const pool_guard_base& pool_guard; // default hash function template<typename T> inline size_t lock_hash(T const& obj, size_t lock_count) { return (reinterpret_cast<size_t>(&obj) / sizeof(T)) % lock_count; } class write_starvation_lock { public: write_starvation_lock::write_starvation_lock() : locks_(0), waiting_readers_(0) {} write_starvation_lock(const write_starvation_lock&) = delete; write_starvation_lock& operator =(const write_starvation_lock&) = delete; void write_starvation_lock::rdlock() { std::unique_lock<std::mutex> lock(mtx_); ++waiting_readers_; while(locks_ < 0) read_condition_.wait(lock); --waiting_readers_; ++locks_; } void write_starvation_lock::lock() { std::unique_lock<std::mutex> lock(mtx_); while(locks_ != 0) write_condition_.wait(lock); locks_ = -1; } void write_starvation_lock::unlock() { std::unique_lock<std::mutex> lock(mtx_); // reader unlock if(locks_ > 0) { --locks_; if(locks_ == 0) write_condition_.notify_one(); } // writer unlock else { locks_ = 0; if(waiting_readers_ != 0) read_condition_.notify_all(); else write_condition_.notify_one(); } } private: std::mutex mtx_; std::condition_variable read_condition_; std::condition_variable write_condition_; int locks_; int waiting_readers_; }; inline void lock_for_reading(std::mutex& mtx) { mtx.lock(); } inline void lock_for_reading(write_starvation_lock& mtx) { mtx.rdlock(); } template<typename pool_type, bool read, class T> class pool_guard_one : public pool_guard_base { pool_type& pool_; const size_t hash_; mutable bool owns_lock_; void lock() const { if(read) pool_.rdlock(hash_); else pool_.lock(hash_); owns_lock_ = true; } void unlock() const { pool_.unlock(hash_); owns_lock_ = false; } public: pool_guard_one(pool_type& pool, T const& obj) : pool_(pool) , owns_lock_(false) { using namespace syncope; hash_ = lock_hash(obj, pool_type::lock_count); lock(); } pool_guard_one(pool_guard_one const&) = delete; pool_guard_one& operator = (pool_guard_one const&) = delete; pool_guard_one(pool_guard_one&& other) : pool_(other.pool_) , hash_(other.hash_) , owns_lock_(other.owns_lock_) { other.owns_lock_ = false; } pool_guard_one& operator = (pool_guard_one&& other) { value_ = other.value_; other.owns_lock_ = false; assert(&pool_ == &other.pool_); } ~pool_guard_one() { if(owns_lock_) { unlock(); } } }; template<typename pool_type, bool read, typename... T> class pool_guard_many : public pool_guard_base { enum { H = sizeof...(T) // hashes array size (can be greater than sizeof...(T)) }; pool_type& pool_; typedef std::array<size_t, H> hash_array; hash_array hashes_; size_t hash_count_; template<size_t I> struct fill_hashes { void operator () (std::array<size_t, H>& hashes, std::tuple<T const&...> const& items) { using namespace syncope; hashes[I] = lock_hash(std::get<I>(items), pool_type::lock_count); fill_hashes<I+1>()(hashes, items); } }; template<> struct fill_hashes<H>{ void operator() (std::array<size_t, H>& hashes, std::tuple<T const&...> const& items) {} }; void lock() { for(size_t i = 0; i < hash_count_; ++i) { if(read) pool_.rdlock(hashes_[i]); else pool_.lock(hashes_[i]); } } void unlock() { while(hash_count_) { pool_.unlock(hashes_[--hash_count_]); } } public: pool_guard_many(pool_type& pool, T const&... objects) : pool_(pool) { auto all = std::tie(objects...); fill_hashes<0> fill_all; fill_all(hashes_, all); std::sort(hashes_.begin(), hashes_.end()); hash_array::iterator it = std::unique(hashes_.begin(), hashes_.end()); hash_count_ = std::distance(hashes_.begin(), it); lock(); } ~pool_guard_many() { if(hash_count_) { unlock(); } } pool_guard_many(pool_guard_many const&) = delete; pool_guard_many& operator = (pool_guard_many const&) = delete; pool_guard_many(pool_guard_many&& other) : pool_(other.pool_) , hash_count_(other.hash_count_) { std::swap(hashes_, other.hashes_); other.hash_count_ = 0; } pool_guard_many& operator = (pool_guard_many&& other) { assert(&other.pool_ == &pool_); std::swap(hashes_, other.hashes_); hash_count_ = other.hash_count_; other.hash_count_ = 0; } }; template<typename t_lock, size_t count> class lock_pool { typedef lock_pool<t_lock, count> pool_type; mutable std::array<t_lock, count> locks_; const char* name_; public: static const size_t lock_count = count; public: lock_pool(const char* name) : name_(name) {} lock_pool(lock_pool const&) = delete; lock_pool& operator = (lock_pool const&) = delete; void lock(size_t hash) const { std::cout << name_ << " lock " << hash << std::endl; locks_[hash].lock(); } void rdlock(size_t hash) const { std::cout << name_ << " read lock " << hash << std::endl; using namespace syncope; lock_for_reading(locks_[hash]); } void unlock(size_t hash) const { std::cout << name_ << " unlock " << hash << std::endl; locks_[hash].unlock(); } template<typename T> pool_guard_one<pool_type, false, T> synchronize(T const& arg) { return std::move(pool_guard_one<pool_type, false, T>(*this, arg)); } template<typename... T> pool_guard_many<pool_type, false, T...> synchronize(T const&... args) { return std::move(pool_guard_many<pool_type, false, T...>(*this, args...)); } template<typename T> pool_guard_one<pool_type, true, T> synchronize_read(T const& arg) { return std::move(pool_guard_one<pool_type, true, T>(*this, arg)); } template<typename... T> pool_guard_many<pool_type, true, T...> synchronize_read(T const&... args) { return std::move(pool_guard_many<pool_type, true, T...>(*this, args...)); } }; } // namespace syncope
Private
[
?
]
Run code
Submit