1
0
forked from Alepha/Alepha
Files
Alepha/Thread.h

175 lines
4.1 KiB
C++

static_assert( __cplusplus > 2020'99 );
#pragma once
#include <Alepha/Alepha.h>
#include <mutex>
#include <stop_token>
#include <functional>
#include <exception>
#include <Alepha/Exception.h>
namespace Alepha::Hydrogen ::detail:: Thread_m
{
inline namespace exports
{
using CrossThreadNotificationRethrowError= synthetic_exception< struct cross_thread_notification_failure, Error >;
namespace this_thread
{
//void sleep( std::chrono::duration );
}
struct ThreadInterrupted;
class Thread;
using thread= Thread;
class ConditionVariable;
using condition_variable= ConditionVariable;
/*!
* An `Interlock` is kind of like a condition variable, for two cooperating threads.
*
* An `Interlock` object represents the state which permits two cooperating threads to
* perform a synchronization action. Each side enters `Interlock::interlock`, and
* when both of them have entered, the synchronization function will be executed.
*
* In some sense it is similar to a `std::barrier` with a capacity to be interrupted
* and accepts parameter to pass as the interlock-synchronization action.
*/
class Interlock;
using std::mutex;
using std::lock_guard;
using std::unique_lock;
}
class exports::Interlock
{
private:
struct Impl;
std::unique_ptr< Impl > pimpl;
auto &impl() { return *pimpl; }
const auto &impl() const { return *pimpl; }
bool waiter( unique_lock< mutex > & );
void interlock( unique_lock< mutex > &lock );
void noblock( unique_lock< mutex > &lock );
public:
~Interlock();
Interlock();
/*!
* Wait on interlock condition.
*
* Blocks this thread until another thread also rendezvous
* with this `Interlock`. If there already is another thread
* waiting, then that thread will be reawakened after the
* `synchronize` step.
*
* @param lock A lock on a mutex which governs exclusive
* access to the shared state among these threads.
*
* @param synchronize The action to take which
* resynchronizes the state among these threads.
*
* @note This operation is an `interruption_point`
*/
void
wait( unique_lock< mutex > &lock, auto &&synchronize )
{
if( waiter( lock ) ) synchronize();
interlock( lock );
}
/*!
* Notify but don't Wait on interlock condition.
*
* Marks that a thread has reached another this rendezvous
* with this `Interlock`. If there already is another thread
* waiting, then that thread will be reawakened after the
* `synchronize` step.
*
* @param lock A lock on a mutex which governs exclusive
* access to the shared state among these threads.
*
* @param synchronize The action to take which
* resynchronizes the state among these threads.
*
* @note This operation is not an `interruption_point`
*/
void
checkpoint( unique_lock< mutex > &lock, auto &&synchronize )
{
if( waiter( lock ) ) synchronize();
noblock( lock );
}
};
class exports::ConditionVariable
{
private:
struct Impl;
std::unique_ptr< Impl > pimpl;
auto &impl() { return *pimpl; }
const auto &impl() const { return *pimpl; }
public:
~ConditionVariable();
ConditionVariable();
void wait( unique_lock< mutex > & );
void
wait( unique_lock< mutex > &lock, auto predicate )
{
while( not predicate() ) wait( lock );
}
void notify_one();
void notify_all();
};
struct exports::ThreadInterrupted {};
class exports::Thread
{
private:
struct Impl;
std::unique_ptr< Impl > pimpl;
auto &impl() { return *pimpl; }
const auto &impl() const { return *pimpl; }
void notify( std::exception_ptr );
public:
~Thread();
explicit Thread( std::function< void () > start );
template< typename Notification >
void
notify( Notification notification )
{
notify( std::make_exception_ptr( std::move( notification ) ) );
}
void
interrupt()
{
notify( std::make_exception_ptr( ThreadInterrupted{} ) );
}
void join();
};
}
namespace Alepha::Hydrogen::inline exports::inline Thread_m
{
using namespace detail::Thread_m::exports;
}