// Header
#pragma once
#include <mutex>
#include <condition_variable>
#include <functional>
struct xbarrier
{
struct arrival_token
{
arrival_token() noexcept = default;
arrival_token( const arrival_token &tk ) noexcept;
arrival_token &operator =( const arrival_token &tk ) noexcept;
operator unsigned() const noexcept;
private:
friend struct xbarrier;
arrival_token( unsigned id ) noexcept;
int id = -1;
};
template<typename Complete>
xbarrier( unsigned initial, Complete &&complete );
xbarrier( const xbarrier & ) = delete;
xbarrier &operator =( const xbarrier & ) = delete;
template<bool Wait = true, bool Drop = false>
arrival_token arrive( arrival_token tk, unsigned count = 1 );
private:
std::mutex m_mtx;
std::condition_variable m_cv;
unsigned m_initial, m_ctr, m_gen;
std::function<void ()> m_complete;
};
template<typename Complete>
xbarrier::xbarrier( unsigned initial, Complete &&complete ) :
m_initial( initial ),
m_ctr( initial ),
m_gen( 0 ),
m_complete( std::forward<Complete>( complete ) )
{
}
inline xbarrier::arrival_token::arrival_token( const arrival_token &tk ) noexcept :
id( tk.id )
{
}
inline xbarrier::arrival_token &xbarrier::arrival_token::operator =(
const arrival_token &tk ) noexcept
{
id = tk.id;
return *this;
}
inline xbarrier::arrival_token::operator unsigned() const noexcept
{
return id;
}
inline xbarrier::arrival_token::arrival_token( unsigned id ) noexcept :
id( id )
{
}
// Cpp
#pragma once
#include "xbarrier.h"
using namespace std;
template<bool Wait, bool Drop>
auto xbarrier::arrive( arrival_token tk, unsigned count ) -> arrival_token
{
if( !count )
return tk;
unique_lock lock( m_mtx );
if constexpr( Drop )
if( m_initial )
--m_initial;
else
return tk;
m_ctr = m_ctr >= count ? m_ctr - count : 0;
unsigned id = m_ctr, gen = m_gen;
if( !m_ctr )
{
m_ctr = 0;
++m_gen;
}
m_ctr = m_ctr ? m_ctr : m_initial;
if( m_ctr == m_initial )
m_cv.notify_all();
else
if constexpr( Wait )
m_cv.wait( lock, [&] { return gen != m_gen; } );
if( tk.id < 0 )
tk.id = id;
if( !tk.id )
m_complete();
return tk;
}
template auto xbarrier::arrive<false, false>( arrival_token, unsigned )
arrival_token;
template auto xbarrier::arrive<true, false>( arrival_token, unsigned )
arrival_token;
template auto xbarrier::arrive<false, true>( arrival_token, unsigned )
arrival_token;
template auto xbarrier::arrive<true, true>( arrival_token, unsigned ) -> arrival_token;
That's pure beauty !
--- PyGate Linux v1.5.2
* Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)