MotorControlModuleSDFM_TMS3.../Projects/EFC_Communication/UMLibrary/common/ResourceKeeper.hpp
2024-06-07 11:12:56 +03:00

304 lines
6.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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_ */