304 lines
6.6 KiB
C++
304 lines
6.6 KiB
C++
/*
|
||
|
||
* ResourceKeeper.hpp
|
||
*
|
||
* Created on: 29 пїЅпїЅпїЅ. 2018 пїЅ.
|
||
* Author: titov
|
||
*/
|
||
|
||
#ifndef SOURCE_COMMON_RESOURCEKEEPER_HPP_
|
||
#define SOURCE_COMMON_RESOURCEKEEPER_HPP_
|
||
|
||
#include <atomic>
|
||
#include <cstddef>
|
||
|
||
//!Класс защиты ресурсов от множественного использования.
|
||
/*!Класс обеспечивает возможность захватить ресурс для уникального использования.
|
||
* Хранит не владеющую ссылку на ресурс, и признак использования.
|
||
*/
|
||
template<typename T>
|
||
class ResourceKeeper {
|
||
protected:
|
||
T & resource; //!<Защищаемый ресурс.
|
||
std::atomic_flag & usable; //!<Признак использования.
|
||
|
||
public:
|
||
ResourceKeeper( T & resource, std::atomic_flag & flag );
|
||
|
||
virtual T * grab(); //!<Функция захвата ресурса для уникального использования.
|
||
const T & show(); //!<Функция получения доступа к данным ресурса.
|
||
virtual void release( T * & ) noexcept; //!<Функция освобождения ресурса.
|
||
|
||
bool is_owned( T * p ) const noexcept;
|
||
|
||
virtual ~ResourceKeeper() = default;
|
||
};
|
||
|
||
template<typename T>
|
||
inline ResourceKeeper<T>::ResourceKeeper( T & r, std::atomic_flag & flag ) : resource(r), usable(flag) {
|
||
usable.clear();
|
||
}
|
||
|
||
template<typename T>
|
||
inline T * ResourceKeeper<T>::grab() {
|
||
|
||
T * result = nullptr;
|
||
|
||
//todo: Решить проблемму множественного граба с разных cpu.
|
||
|
||
if( !usable.test_and_set() )
|
||
result = &resource;
|
||
|
||
return result;
|
||
}
|
||
|
||
template<typename T>
|
||
inline const T & ResourceKeeper<T>::show() {
|
||
|
||
return resource;
|
||
|
||
}
|
||
|
||
template<typename T>
|
||
inline void ResourceKeeper<T>::release( T * & arg ) noexcept {
|
||
|
||
if( arg == &resource ) {
|
||
arg = nullptr;
|
||
usable.clear();
|
||
}
|
||
|
||
}
|
||
|
||
template<typename T>
|
||
class Local {
|
||
private:
|
||
T * resource; //!<Защищаемый ресурс.
|
||
ResourceKeeper<T> * keeper;
|
||
|
||
Local( const Local &) = delete;
|
||
Local & operator=( const Local & ) = delete;
|
||
public:
|
||
Local( T * res, ResourceKeeper<T> & keep );
|
||
Local( ResourceKeeper<T> * );
|
||
~Local() noexcept;
|
||
|
||
T * operator->();
|
||
explicit operator bool() {
|
||
return resource;
|
||
}
|
||
|
||
void release( T * & );
|
||
//Замена хранимого ресурса. Для предыдущего будет вызван метод release
|
||
void reset(T * &);
|
||
};
|
||
|
||
template<typename T>
|
||
inline Local<T>::Local( T * res, ResourceKeeper<T> & keep ) :
|
||
resource(res), keeper(&keep) {}
|
||
|
||
template<typename T>
|
||
inline Local<T>::~Local() noexcept {
|
||
|
||
if( resource and keeper )
|
||
keeper->release( resource );
|
||
|
||
}
|
||
|
||
template<typename T>
|
||
inline Local<T>::Local( ResourceKeeper<T> * keep ) :
|
||
keeper(keep), resource(keep ? keep->grab() : nullptr) {}
|
||
|
||
template<typename T>
|
||
inline T * Local<T>::operator ->() {
|
||
|
||
return resource;
|
||
|
||
}
|
||
|
||
|
||
template<typename T>
|
||
inline T * grab( ResourceKeeper<T> * rk ) {
|
||
|
||
return rk ? rk->grab() : nullptr;
|
||
|
||
}
|
||
|
||
template<typename T>
|
||
inline const T * show( ResourceKeeper<T> * rk ) {
|
||
|
||
return rk ? &rk->show() : nullptr;
|
||
|
||
}
|
||
|
||
template<typename T>
|
||
inline bool grab( T * & res, ResourceKeeper<T> * rk ) {
|
||
T * new_ptr = ( rk ? rk->grab() : nullptr );
|
||
res = res ? res : new_ptr;
|
||
return res;
|
||
}
|
||
|
||
template<typename T>
|
||
inline bool show( const T * & res, ResourceKeeper<T> * rk ) {
|
||
const T * new_ptr = ( rk ? &rk->show() : nullptr );
|
||
res = res ? res : new_ptr;
|
||
return res;
|
||
}
|
||
|
||
template<typename T>
|
||
inline void release( ResourceKeeper<T> * rk, T * k ) {
|
||
|
||
if( rk and k ) rk->release( k );
|
||
|
||
}
|
||
|
||
template<typename T>
|
||
inline void Local<T>::release( T * & new_owner ) {
|
||
|
||
T * temp = resource;
|
||
resource = nullptr;
|
||
new_owner = temp;
|
||
|
||
}
|
||
|
||
|
||
template<typename T>
|
||
inline void Local<T>::reset( T * & new_resource ) {
|
||
|
||
if( resource and keeper )
|
||
keeper->release( resource );
|
||
resource = new_resource;
|
||
}
|
||
|
||
struct LocableInterface {
|
||
virtual bool try_lock() = 0;
|
||
virtual void unlock() = 0;
|
||
virtual ~LocableInterface() = default;
|
||
};
|
||
|
||
template<typename T>
|
||
class Locable : public LocableInterface {
|
||
public:
|
||
Locable( ResourceKeeper<T> & keeper );
|
||
~Locable() noexcept;
|
||
|
||
T * operator->() const;
|
||
T * pointer() const;
|
||
const T & show() const;
|
||
explicit operator bool() const {
|
||
return resource;
|
||
}
|
||
|
||
bool try_lock();
|
||
void unlock() noexcept;
|
||
|
||
private:
|
||
T * resource;
|
||
ResourceKeeper<T> & keeper;
|
||
|
||
Locable( const Locable &) = delete;
|
||
Locable & operator=( const Locable & ) = delete;
|
||
};
|
||
|
||
template<typename T>
|
||
inline Locable<T>::Locable( ResourceKeeper<T> & keeper ) : keeper(keeper), resource(nullptr) {}
|
||
|
||
template<typename T>
|
||
inline Locable<T>::~Locable() noexcept {
|
||
keeper.release( resource );
|
||
}
|
||
|
||
template<typename T>
|
||
inline T * Locable<T>::operator->() const {
|
||
return resource;
|
||
}
|
||
|
||
template<typename T>
|
||
inline const T & Locable<T>::show() const {
|
||
|
||
return keeper.show();
|
||
|
||
}
|
||
|
||
template<typename T>
|
||
inline bool Locable<T>::try_lock() {
|
||
|
||
resource = keeper.grab();
|
||
|
||
return resource;
|
||
}
|
||
|
||
template<typename T>
|
||
inline T * Locable<T>::pointer() const {
|
||
|
||
return resource;
|
||
|
||
}
|
||
|
||
template<typename T>
|
||
inline void Locable<T>::unlock() noexcept {
|
||
|
||
keeper.release( resource );
|
||
|
||
}
|
||
|
||
template<typename ... Args>
|
||
struct ScopeLock {
|
||
|
||
ScopeLock( Args & ... args );
|
||
explicit operator bool();
|
||
void freeze();
|
||
~ScopeLock() noexcept;
|
||
|
||
private:
|
||
bool is_locked;
|
||
bool frozen;
|
||
std::size_t counter;
|
||
|
||
LocableInterface * locable[ sizeof...(Args) ];
|
||
|
||
int add( LocableInterface & );
|
||
};
|
||
|
||
template<typename ... Args>
|
||
inline ScopeLock<Args...>::ScopeLock( Args & ... args ) : is_locked( true ), frozen( false ), counter( 0 ) {
|
||
int temp[] = { add(args)... };
|
||
}
|
||
|
||
template<typename ... Args>
|
||
inline ScopeLock<Args...>::operator bool() {
|
||
|
||
return is_locked;
|
||
|
||
}
|
||
|
||
template<typename ... Args>
|
||
inline ScopeLock<Args...>::~ScopeLock() noexcept {
|
||
if( not is_locked or not frozen ) {
|
||
for( std::size_t i = 0; i < counter; i++ )
|
||
locable[i]->unlock();
|
||
}
|
||
}
|
||
|
||
template<typename ... Args>
|
||
inline int ScopeLock<Args...>::add( LocableInterface & lc ) {
|
||
|
||
if( is_locked and ( is_locked = lc.try_lock() ) )
|
||
locable[counter++] = &lc;
|
||
|
||
return is_locked;
|
||
}
|
||
|
||
template<typename ... Args>
|
||
inline void ScopeLock<Args...>::freeze() {
|
||
frozen = true;
|
||
}
|
||
|
||
template<typename T>
|
||
inline bool ResourceKeeper<T>::is_owned( T * pointer ) const noexcept {
|
||
|
||
return pointer == &resource;
|
||
|
||
}
|
||
|
||
#endif /* SOURCE_COMMON_RESOURCEKEEPER_HPP_ */
|