static_assert( __cplusplus > 2020'99 ); #pragma once #include #include #include #include #include #include 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; }