2017-09-25 14:43:32 +02:00
|
|
|
#ifndef _LOCKED_WAIT_H
|
|
|
|
#define _LOCKED_WAIT_H
|
|
|
|
|
|
|
|
#include <condition_variable>
|
|
|
|
#include <mutex>
|
|
|
|
#include <queue>
|
|
|
|
#include <atomic>
|
|
|
|
#include <type_traits>
|
2017-09-30 23:51:01 +02:00
|
|
|
#include <utility>
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-11-29 16:55:48 +01:00
|
|
|
namespace Sapphire
|
2017-09-25 14:43:32 +02:00
|
|
|
{
|
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
template< typename T >
|
|
|
|
class LockedWaitQueue
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2018-10-28 21:53:21 +01:00
|
|
|
private:
|
|
|
|
std::mutex m_queueLock;
|
|
|
|
std::queue< T > m_queue;
|
|
|
|
std::condition_variable m_condition;
|
|
|
|
std::atomic< bool > m_shutdown;
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
public:
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
LockedWaitQueue< T >() :
|
|
|
|
m_shutdown( false )
|
|
|
|
{
|
|
|
|
}
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
void push( const T& value )
|
|
|
|
{
|
|
|
|
std::lock_guard< std::mutex > lock( m_queueLock );
|
|
|
|
m_queue.push( std::move( value ) );
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
m_condition.notify_one();
|
|
|
|
}
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
bool empty()
|
|
|
|
{
|
|
|
|
std::lock_guard< std::mutex > lock( m_queueLock );
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
return m_queue.empty();
|
|
|
|
}
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
bool pop( T& value )
|
|
|
|
{
|
|
|
|
std::lock_guard< std::mutex > lock( m_queueLock );
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
if( m_queue.empty() || m_shutdown )
|
|
|
|
return false;
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
value = m_queue.front();
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
m_queue.pop();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
void waitAndPop( T& value )
|
|
|
|
{
|
|
|
|
std::unique_lock< std::mutex > lock( m_queueLock );
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
while( m_queue.empty() && !m_shutdown )
|
|
|
|
m_condition.wait( lock );
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
if( m_queue.empty() || m_shutdown )
|
|
|
|
return;
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
value = m_queue.front();
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
m_queue.pop();
|
|
|
|
}
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
void cancel()
|
2018-08-29 21:40:59 +02:00
|
|
|
{
|
2018-10-28 21:53:21 +01:00
|
|
|
std::unique_lock< std::mutex > lock( m_queueLock );
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
while( !m_queue.empty() )
|
|
|
|
{
|
|
|
|
T& value = m_queue.front();
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
deleteQueuedObject( value );
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
m_queue.pop();
|
|
|
|
}
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
m_shutdown = true;
|
2017-09-25 14:43:32 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
m_condition.notify_all();
|
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
|
2018-10-28 21:53:21 +01:00
|
|
|
private:
|
|
|
|
template< typename E = T >
|
|
|
|
typename std::enable_if< std::is_pointer< E >::value >::type deleteQueuedObject( E& obj )
|
|
|
|
{
|
|
|
|
delete obj;
|
|
|
|
}
|
|
|
|
|
|
|
|
template< typename E = T >
|
|
|
|
typename std::enable_if< !std::is_pointer< E >::value >::type deleteQueuedObject( E const& )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
};
|
2017-09-25 14:43:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|