forked from Alepha/Alepha
175 lines
4.1 KiB
C++
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;
|
|
}
|