#pragma once #include #include #include #include #include #include namespace std { template struct lock_guarded { Lock l; T *t; T *operator->() &&{ return t; } template auto operator[](Arg &&arg) && -> decltype(std::declval()[std::declval()]) { return (*t)[std::forward(arg)]; } T &operator*() &&{ return *t; } }; template struct lock_guarded_shared { Lock l; std::shared_ptr t; T *operator->() &&{ return t.operator->(); } template auto operator[](Arg &&arg) && -> decltype(std::declval()[std::declval()]) { return (*t)[std::forward(arg)]; } T &operator*() &&{ return *t; } operator bool() { return !!t; } bool operator !() { return !t; } }; constexpr struct emplace_t { } emplace{}; template struct observer_locked { public: observer_locked(observer_locked &&o) : t(std::move(o.t)), m(std::move(o.m)) {} observer_locked(observer_locked const &o) : t(o.t), m(o.m) {} observer_locked(M lock,T entry) : m(std::forward(lock)), t(std::forward(entry)) {} observer_locked() = default; ~observer_locked() = default; T operator->() { return t; } T const operator->() const { return t; } T get() { return this->t; } T const get() const { return this->t; } template std::result_of_t operator->*(F &&f) { return std::forward(f)(t); } template std::result_of_t operator->*(F &&f) const { return std::forward(f)(t); } observer_locked &operator=(observer_locked &&o) { this->m = std::move(o.m); this->t = std::move(o.t); return *this; } observer_locked &operator=(observer_locked const &o) { this->m = o.m; this->t = o.t; return *this; } observer_locked &reset() { observer_locked empty(M(),NULL); *this = empty; return *this; } private: M m; T t; }; template struct mutex_guarded { lock_guarded> get_locked() { return {std::unique_lock{m}, &t}; } lock_guarded> get_locked() const { return {{m}, &t}; } lock_guarded> operator->() { return get_locked(); } lock_guarded> operator->() const { return get_locked(); } template std::result_of_t operator->*(F &&f) { return std::forward(f)(*get_locked()); } template std::result_of_t operator->*(F &&f) const { return std::forward(f)(*get_locked()); } template mutex_guarded(emplace_t, Args &&...args) : t(std::forward(args)...) {} mutex_guarded(mutex_guarded &&o) : t(std::move(*o.get_locked())) {} mutex_guarded(mutex_guarded const &o) : t(*o.get_locked()) {} mutex_guarded() = default; ~mutex_guarded() = default; mutex_guarded &operator=(mutex_guarded &&o) { T tmp = std::move(o.get_locked()); *get_locked() = std::move(tmp); return *this; } mutex_guarded &operator=(mutex_guarded const &o) { T tmp = o.get_locked(); *get_locked() = std::move(tmp); return *this; } private: std::mutex m; T t; }; class shared_recursive_mutex { std::shared_mutex handle; public: void lock(void) { std::thread::id this_id = std::this_thread::get_id(); if (owner == this_id) { // recursive locking ++count; } else { // normal locking if (shared_counts->count(this_id)) {//Already shared locked, write lock is not available #ifdef WIN32 throw std::logic_error("resource_deadlock_would_occur"); #else __throw_system_error(int(errc::resource_deadlock_would_occur)); #endif } handle.lock(); //Now wait until everyone else has finished owner = this_id; count = 1; } } void unlock(void) { std::thread::id this_id = std::this_thread::get_id(); assert(this_id == this->owner); if (count > 1) { // recursive unlocking count--; } else { // normal unlocking owner = this_id; count = 0; handle.unlock(); } } void lock_shared() { std::thread::id this_id = std::this_thread::get_id(); if(this->owner == this_id) { #ifdef WIN32 throw std::logic_error("resource_deadlock_would_occur"); #else __throw_system_error(int(errc::resource_deadlock_would_occur)); #endif } if (shared_counts->count(this_id)) { ++(shared_counts.get_locked()[this_id]); } else { handle.lock_shared(); shared_counts.get_locked()[this_id] = 1; } } void unlock_shared() { std::thread::id this_id = std::this_thread::get_id(); auto it = shared_counts->find(this_id); if (it->second > 1) { --(it->second); } else { shared_counts->erase(it); handle.unlock_shared(); } } bool try_lock() { std::thread::id this_id = std::this_thread::get_id(); if (owner == this_id) { // recursive locking ++count; return true; } else { // normal locking if (shared_counts->count(this_id)){ //Already shared locked, write lock is not available #ifdef WIN32 throw std::logic_error("resource_deadlock_would_occur"); #else __throw_system_error(int(errc::resource_deadlock_would_occur)); #endif } if(!handle.try_lock()) return false; owner = this_id; count = 1; return true; } } bool try_lock_shared() { std::thread::id this_id = std::this_thread::get_id(); if(this->owner == this_id){ #ifdef WIN32 throw std::logic_error("resource_deadlock_would_occur"); #else __throw_system_error(int(errc::resource_deadlock_would_occur)); #endif } if (shared_counts->count(this_id)) { ++(shared_counts.get_locked()[this_id]); } else { if(!handle.try_lock_shared()) return false; shared_counts.get_locked()[this_id] = 1; } return true; } private: std::atomic owner; std::atomic count; mutex_guarded> shared_counts; }; template inline bool mutex_locked(T& mutex) { return true; try { unique_lock lock_try(mutex, try_to_lock); /* should throw EDEADLK */ return false; } catch(const std::system_error& ex) { return ex.code() == errc::resource_deadlock_would_occur; } } template inline bool mutex_shared_locked(T& mutex) { return true; try { shared_lock lock_try(mutex, try_to_lock); /* should throw EDEADLK */ return false; } catch(const std::system_error& ex) { return ex.code() == errc::resource_deadlock_would_occur; } } }