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

217
Thread.h
View File

@ -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= &notification;
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;
}