/******************************************************************************/ /* THREADING ******************************************************************/ /******************************************************************************/ #ifndef _H_EBCL_THREADING #define _H_EBCL_THREADING #include #include namespace ebcl { /*= ALIASES ==================================================================*/ using T_Mutex = std::mutex; using T_ScopeLock = std::lock_guard< std::mutex >; using T_ExclusiveLock = std::unique_lock< std::mutex >; using T_Condition = std::condition_variable; using T_Thread = std::thread; M_CLASS_POINTERS( Mutex ); M_CLASS_POINTERS( ExclusiveLock ); M_CLASS_POINTERS( Condition ); M_CLASS_POINTERS( Thread ); /*= READ/WRITE LOCKING =======================================================*/ // A mutex that supports multiple readers and one writer. Based on the // implementation from G++ 6's standard library. class T_ReadWriteMutex { private: static constexpr uint32_t C_WLOCKED_ = 1 << 31; static constexpr uint32_t C_READERS_ = ~C_WLOCKED_; T_Mutex mutex_; T_Condition readerBlock_; T_Condition writerBlock_; uint32_t state_; public: T_ReadWriteMutex( ); T_ReadWriteMutex( T_ReadWriteMutex const& ) = delete; T_ReadWriteMutex( T_ReadWriteMutex&& ) = default; ~T_ReadWriteMutex( ); T_ReadWriteMutex& operator=( T_ReadWriteMutex const& ) = delete; T_ReadWriteMutex& operator=( T_ReadWriteMutex&& ) = default; // --------------------------------------------------------------------- // Write lock void lock( ); bool try_lock( ); void unlock( ); // --------------------------------------------------------------------- // Read lock void lock_shared( ); bool try_lock_shared( ); void unlock_shared( ); // --------------------------------------------------------------------- void upgradeLock( ); }; M_CLASS_POINTERS( ReadWriteMutex ); // Write lock / scoped write lock aliases using T_WriteLock = std::unique_lock< T_ReadWriteMutex >; using T_ScopeWriteLock = std::lock_guard< T_ReadWriteMutex >; M_CLASS_POINTERS( WriteLock ); // Read lock based on std::shared_lock, but that can be // upgraded to a write lock without releasing class T_ReadLock : public std::shared_lock< T_ReadWriteMutex > { public: T_ReadLock( ) noexcept; T_ReadLock( T_ReadLock&& other ); explicit T_ReadLock( T_ReadWriteMutex& m ); T_ReadLock( T_ReadWriteMutex& m , std::defer_lock_t t ); T_ReadLock( T_ReadWriteMutex& m , std::try_to_lock_t t ); T_ReadLock( T_ReadWriteMutex& m , std::adopt_lock_t t ); T_WriteLock upgrade( ); }; M_CLASS_POINTERS( ReadLock ); /*= RING BUFFER ==============================================================*/ template< typename ElementType > class T_RingBuffer { private: typedef T_RingBuffer< ElementType > T_Self; uint32_t expand_; ElementType * data_; uint32_t allocated_; uint32_t used_; uint32_t readPos_; public: M_TEMPLATE_POINTERS( T_Self ); explicit T_RingBuffer( uint32_t expand = 64 ); T_RingBuffer( T_Self const& other ); T_RingBuffer( T_Self&& other ) noexcept; ~T_RingBuffer( ); T_Self& operator=( T_Self const& other ); T_Self& operator=( T_Self&& other ) noexcept; template< typename T > friend void swap( T_RingBuffer< T >& lhs , T_RingBuffer< T >& rhs ) noexcept; void free( ); uint32_t size( ) const; uint32_t capacity( ) const; uint32_t growth( ) const; bool readNext( ElementType& output ); bool readAll( T_Array< ElementType >& output ); void put( ElementType const& input ); void put( ElementType&& input ); template< typename... ArgTypes > void putNew( ArgTypes&&... arguments ); private: void expand( ); }; template< typename T > void swap( T_RingBuffer< T >& lhs , T_RingBuffer< T >& rhs ) noexcept; } #endif // _H_EBCL_THREADING #include