1
0
forked from Alepha/Alepha

Modernize thread code.

This commit is contained in:
2023-11-14 15:04:04 -05:00
parent c6b66aa7b5
commit b8d6c5aced
4 changed files with 208 additions and 149 deletions

130
Thread.cc Normal file
View File

@ -0,0 +1,130 @@
static_assert( __cplusplus > 2020'99 );
#include "Thread.h"
#include <stop_token>
#include <condition_variable>
#include <Alepha/Utility/StaticValue.h>
#include <Alepha/Utility/evaluation_helpers.h>
namespace Alepha::Hydrogen::detail::Thread_m
{
namespace
{
struct ThreadState
{
std::mutex access;
std::stop_source source;
std::exception_ptr notification;
void
deliver( std::exception_ptr ptr )
{
std::lock_guard lock{ access };
if( notification ) return; // TODO: Don't swallow blocked interrupts?
notification= std::move( ptr );
source.request_stop();
}
void
interruption_point( std::lock_guard< std::mutex > & )
{
if( notification == nullptr ) return;
source= std::stop_source{};
auto next= std::move( notification );
notification= nullptr;
std::rethrow_exception( next );
}
void
interruption_point()
{
std::lock_guard lock( access );
interruption_point( lock );
}
std::stop_token
getToken()
{
std::lock_guard lock( access );
interruption_point( lock );
return source.get_token();
}
};
thread_local Utility::StaticValue< std::shared_ptr< ThreadState > > state;
}
struct ConditionVariable::Impl
{
std::condition_variable_any cond;
};
ConditionVariable::~ConditionVariable()= default;
ConditionVariable::ConditionVariable()
: pimpl( std::make_unique< Impl >() ) {}
void
ConditionVariable::notify_one()
{
impl().cond.notify_one();
}
void
ConditionVariable::notify_all()
{
impl().cond.notify_all();
}
void
ConditionVariable::wait( unique_lock< mutex > &lock )
{
auto stop= Utility::evaluate <=[]
{
std::lock_guard lock( state()->access );
return state()->source.get_token();
};
impl().cond.wait( lock, stop, [val= std::uint64_t()] mutable { return val++; } );
state()->interruption_point();
}
struct Thread::Impl
{
std::thread thr;
std::weak_ptr< ThreadState > state;
};
Thread::~Thread()= default;
Thread::Thread( std::function< void () > start )
{
auto newState= std::make_shared< ThreadState >();
std::weak_ptr local= newState;
auto entry= [newState= std::move( newState ), start= std::move( start )]
{
state()= std::move( newState );
start();
};
pimpl= std::make_unique< Impl >( std::thread{ std::move( entry ) }, std::move( local ) );
}
void
Thread::join()
{
// TODO: Make interruptible.
impl().thr.join();
}
void
Thread::notify( std::exception_ptr p )
{
const auto state= impl().state.lock();
if( not state ) return;
state->deliver( std::move( p ) );
}
}