forked from Alepha/Alepha
Modernize thread code.
This commit is contained in:
217
Thread.h
217
Thread.h
@ -4,165 +4,94 @@ static_assert( __cplusplus > 2020'99 );
|
||||
|
||||
#include <Alepha/Alepha.h>
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <mutex>
|
||||
#include <stop_token>
|
||||
#include <functional>
|
||||
#include <exception>
|
||||
|
||||
#include <Alepha/Exception.h>
|
||||
|
||||
namespace Alepha::Hydrogen
|
||||
namespace Alepha::Hydrogen ::detail:: Thread_m
|
||||
{
|
||||
namespace detail::Thread_m
|
||||
inline namespace exports
|
||||
{
|
||||
inline namespace exports {}
|
||||
namespace exports
|
||||
using CrossThreadNotificationRethrowError= synthetic_exception< struct cross_thread_notification_failure, Error >;
|
||||
namespace this_thread
|
||||
{
|
||||
using CrossThreadNotificationRethrowError= synthetic_exception< struct cross_thread_notification_failure, Error >;
|
||||
//void sleep( std::chrono::duration );
|
||||
}
|
||||
|
||||
class NotificationInfo
|
||||
{
|
||||
private:
|
||||
std::mutex access;
|
||||
std::exception_ptr notification;
|
||||
struct ThreadInterrupted;
|
||||
class Thread;
|
||||
using thread= Thread;
|
||||
class ConditionVariable;
|
||||
using condition_variable= ConditionVariable;
|
||||
|
||||
public:
|
||||
//template( Concepts::DerivedFrom< Notification > Exc )
|
||||
void
|
||||
setNotification( std::exception_ptr &&exception )
|
||||
{
|
||||
std::lock_guard lock( access );
|
||||
notification= std::move( exception );
|
||||
}
|
||||
using std::mutex;
|
||||
using std::lock_guard;
|
||||
using std::unique_lock;
|
||||
}
|
||||
|
||||
template< typename Callable >
|
||||
void
|
||||
check_interrupt( Callable &&callable )
|
||||
try
|
||||
{
|
||||
callable();
|
||||
}
|
||||
catch( const boost::thread_interrupted & )
|
||||
{
|
||||
std::lock_guard lock( access );
|
||||
if( not notification ) throw;
|
||||
try
|
||||
{
|
||||
std::rethrow_exception( std::move( notification ) );
|
||||
}
|
||||
catch( const std::bad_alloc & )
|
||||
{
|
||||
throw build_exception< CrossThreadNotificationRethrowError >( "`std::bad_alloc` encountered in trying to "
|
||||
"raise a cross-thread notification" );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline thread_local NotificationInfo notification;
|
||||
class exports::ConditionVariable
|
||||
{
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr< Impl > pimpl;
|
||||
|
||||
namespace exports
|
||||
{
|
||||
class ConditionVariable
|
||||
: private boost::condition_variable
|
||||
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 )
|
||||
{
|
||||
public:
|
||||
using condition_variable::notify_all;
|
||||
using condition_variable::notify_one;
|
||||
|
||||
template< typename Lock >
|
||||
void
|
||||
wait( Lock &&lock )
|
||||
{
|
||||
notification.check_interrupt( [&]{ condition_variable::wait( std::forward< Lock >( lock ) ); } );
|
||||
}
|
||||
|
||||
template< typename Lock, typename Predicate >
|
||||
void
|
||||
wait( Lock &&lock, Predicate &&predicate )
|
||||
{
|
||||
notification.check_interrupt( [&]{ condition_variable::wait( std::forward< Lock >( lock ),
|
||||
std::forward< Predicate >( predicate ) ); } );
|
||||
}
|
||||
};
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
template< typename Clock, typename Duration >
|
||||
void
|
||||
sleep_until( const boost::chrono::time_point< Clock, Duration > &abs_time )
|
||||
{
|
||||
notification.check_interrupt( [&]{ boost::this_thread::sleep_until( abs_time ); } );
|
||||
}
|
||||
|
||||
#if 0
|
||||
template< typename Rep, typename Period >
|
||||
void
|
||||
sleep_for( const boost::chrono::duration< Rep, Period > &rel_time )
|
||||
{
|
||||
notification.check_interrupt( [&]( boost::this_thread::sleep_until( rel_time ); } );
|
||||
}
|
||||
#endif
|
||||
while( not predicate() ) wait( lock );
|
||||
}
|
||||
}
|
||||
|
||||
struct ThreadNotification
|
||||
{
|
||||
NotificationInfo *myNotification= nullptr;
|
||||
};
|
||||
|
||||
namespace exports
|
||||
{
|
||||
class Thread
|
||||
: ThreadNotification, boost::thread
|
||||
{
|
||||
public:
|
||||
template< typename Callable >
|
||||
explicit
|
||||
Thread( Callable &&callable )
|
||||
: thread
|
||||
(
|
||||
[this, callable= std::forward< Callable >( callable )]
|
||||
{
|
||||
myNotification= ¬ification;
|
||||
try { callable(); }
|
||||
catch( const Notification & )
|
||||
{
|
||||
// Notifications are not fatal.
|
||||
}
|
||||
}
|
||||
)
|
||||
{}
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
};
|
||||
|
||||
using thread::join;
|
||||
using thread::detach;
|
||||
|
||||
using thread::interrupt;
|
||||
struct exports::ThreadInterrupted {};
|
||||
|
||||
//template( Concepts::DerivedFrom< Notification > Exc )
|
||||
template< typename Exc >
|
||||
void
|
||||
interrupt( Exc &&exception )
|
||||
try
|
||||
{
|
||||
throw std::forward< Exc >( exception );
|
||||
}
|
||||
catch( const Notification & )
|
||||
{
|
||||
myNotification->setNotification( std::current_exception() );
|
||||
interrupt();
|
||||
}
|
||||
};
|
||||
|
||||
using Mutex= boost::mutex;
|
||||
using boost::mutex;
|
||||
using boost::unique_lock;
|
||||
using boost::lock_guard;
|
||||
}
|
||||
}
|
||||
|
||||
inline namespace exports {}
|
||||
namespace exports::inline Thread_m
|
||||
class exports::Thread
|
||||
{
|
||||
using namespace detail::Thread_m::exports;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user