134 std::string
sanitise (std::string
const&);
153 using std::invoke_result_t;
154 using std::is_constructible;
155 using std::make_from_tuple;
156 using std::tuple_cat;
181 :
threadID_{isnil(threadID)?
"sub-thread" :
util::sanitise (threadID)}
199 template<
class...INVO>
203 ASSERT (not
isLive(),
"Thread already running");
204 threadImpl_ = make_from_tuple<std::thread> (invocation);
247 template<
class BAS,
typename=
void>
253 template<
class FUN,
typename...ARGS>
259 std::invoke (forward<FUN> (callable), forward<ARGS> (args)...);
267 BAS::detach_thread_from_wrapper();
273 BAS::waitGracePeriod();
284 template<
class BAS,
class TAR>
289 using BasePol::BasePol;
304 BasePol::handle_begin_thread();
313 BAS::detach_thread_from_wrapper();
335 template<
class BAS,
typename RES>
345 template<
class FUN,
typename...ARGS>
349 static_assert (__or_<is_same<RES,void>
350 ,is_constructible<RES, invoke_result_t<FUN,ARGS...>>>());
355 ,forward<ARGS>(args)...});
367 ALERT (thread,
"Thread '%s' was not joined. Abort.", BAS::threadID_.c_str());
376 template<
template<
class,
class>
class POL,
typename RES =
void>
378 :
protected POL<ThreadWrapper, RES>
382 template<
typename...ARGS>
386 while (not Policy::isLive())
387 std::this_thread::yield();
388 Policy::handle_begin_thread();
389 Policy::markThreadStart();
390 Policy::perform_thread_function (forward<ARGS> (args)...);
391 Policy::markThreadEnd();
392 Policy::handle_after_thread();
399 if (Policy::isLive())
400 Policy::handle_loose_thread();
413 template<
class W,
class...INVO>
435 template<
class...INVO>
439 tuple<decay_t<INVO>...> argCopy{forward<INVO> (args)...};
440 return [invocation = move(argCopy)]
443 auto boundInvocation = lateBindInstance (wrapper, move (invocation));
444 wrapper.launchThread (
buildInvocation (wrapper, move(boundInvocation)));
463 template<
class FUN,
typename...ARGS>
464 Launch (FUN&& threadFunction, ARGS&& ...args)
468 template<
class TAR,
typename...ARGS>
469 Launch (RES (TAR::*memFun) (ARGS...), ARGS ...args)
471 ,
lib::meta::InstancePlaceholder<TAR>{}
472 ,forward<ARGS> (args)... }
485 id = Policy::decorate_with_global_count (
id);
489 template<
typename HOOK>
493 return addHook (&Policy::hook_beginThread, forward<HOOK> (hook));
496 template<
typename HOOK>
500 return addHook (&Policy::hook_afterThread, forward<HOOK> (hook));
503 template<
typename HOOK>
507 return addHook (&Policy::hook_looseThread, forward<HOOK> (hook));
519 template<
typename HOOK,
class FUN>
529 return [hook = forward<HOOK>(hook)](Arg){ hook(); };
533 return [hook = forward<HOOK>(hook)]
537 Target& target =
static_cast<Target&
> (base);
544 template<
typename HOOK,
class FUN>
548 return addLayer ([storedHook, hook = adaptedHook (storedHook, forward<HOOK> (hook))]
551 wrapper.*storedHook = move (hook);
559 launch = [action=move(action), chain=move(launch)]
590 template<
class FUN,
typename...ARGS>
593 Launch{forward<FUN> (threadFunction), forward<ARGS> (args)...}
601 template<
class SUB,
typename...ARGS>
605 ,static_cast<SUB*> (this)
606 ,forward<ARGS> (args)...
608 .threadID(
util::joinDash (typeSymbol<SUB>(), args...))}
620 operator bool()
const
622 return Policy::isLive();
626 using Policy::invokedWithinThread;
652 using ThreadLifecycle::ThreadLifecycle;
667 template<
typename RES =
void>
687 if (not Impl::threadImpl_.joinable())
690 Impl::threadImpl_.join();
692 return Impl::result_;
697 template<
typename FUN,
typename...ARGS>
720 using ThreadLifecycle::ThreadLifecycle;
740 template<
class TAR = ThreadHookable>
746 new TAR{move(launchBuilder)
747 .atExit([](TAR& selfAllocation)
749 delete &selfAllocation;
763 template<
class TAR = ThreadHookable,
typename...INVO>
767 using Launch = TAR::Launch;
768 launchDetached<TAR> (Launch{forward<INVO> (args)...}
769 .threadID (threadID));
773 template<
class TAR,
typename...ARGS>
775 launchDetached (
string const& threadID,
void (TAR::*memFun) (ARGS...), ARGS ...args)
777 using Launch = TAR::Launch;
778 launchDetached<TAR> (Launch{std::move (memFun)
780 ,forward<ARGS> (args)...
782 .threadID (threadID));
786 template<
class TAR,
typename...ARGS>
792 ,forward<ARGS> (args)...
Representation of the result of some operation, EITHER a value or a failure.
Extended variant of the standard case, allowing to install callbacks (hook functions) to be invoked d...
Variant of the standard case, requiring to wait and join() on the termination of this thread.
lib::Result< RES > join()
put the caller into a blocking wait until this thread has terminated
A thin convenience wrapper to simplify thread-handling.
Policy-based configuration of thread lifecycle.
static auto buildInvocation(W &wrapper, tuple< INVO... > &&invocation)
Build the invocation tuple, using invokeThreadFunction to delegate to the user-provided functor and a...
ThreadLifecycle()
derived classes may create a disabled thread
ThreadLifecycle(string const &threadID, FUN &&threadFunction, ARGS &&...args)
Create a new thread to execute the given operation.
POL< ThreadWrapper, RES > Policy
ThreadLifecycle(RES(SUB::*memFun)(ARGS...), ARGS ...args)
Special variant to bind a subclass member function as thread operation.
ThreadLifecycle(Launch launcher)
Primary constructor: Launch the new thread with flexible configuration.
void invokeThreadFunction(ARGS &&...args)
static auto buildLauncher(INVO &&...args)
Build a λ actually to launch the given thread operation later, after the thread-wrapper-object is ful...
Types marked with this mix-in may be moved but not copied.
Lumiera error handling (C++ interface).
#define ERROR_LOG_AND_IGNORE(_FLAG_, _OP_DESCR_)
convenience shortcut for a sequence of catch blocks just logging and consuming an error.
Metaprogramming tools for detecting and transforming function types.
This header is for including and configuring NoBug.
Implementation namespace for support and library code.
void launchDetached(ThreadHookable::Launch &&launchBuilder)
Launch an autonomous self-managing thread (and forget about it).
LumieraError< LERR_(LOGIC)> Logic
std::string sanitise(std::string const &)
produce an identifier based on the given string.
string joinDash(ARGS const &...args)
shortcut: join directly with dashes
bool isnil(lib::time::Duration const &dur)
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Intermediary value object to represent »either« an operation result or a failure.
void perform_thread_function(FUN &&callable, ARGS &&...args)
void handle_loose_thread()
void handle_after_thread()
Thread Lifecycle Policy Extension: invoke user-provided callbacks from within thread lifecycle.
void handle_loose_thread()
function< void(Self &)> Hook
void handle_after_thread()
void handle_begin_thread()
void perform_thread_function(FUN &&callable, ARGS &&...args)
void handle_loose_thread()
void handle_after_thread()
lib::Result< RES > result_
Wrapper to capture a success/failure indicator and possibly a computation result.
Configuration builder to define the operation running within the thread, and possibly configure furth...
Launch && threadID(string const &threadID)
function< void(ThreadLifecycle &)> Act
Launch && addLayer(Act action)
generic helper to add another »onion layer« to this config builder
Launch && addHook(FUN Policy::*storedHook, HOOK &&hook)
add a config layer to store a user-provided functor into the polic baseclass(es)
Launch && atExit(HOOK &&hook)
Launch && atStart(HOOK &&hook)
Launch && decorateCounter()
Launch(RES(TAR::*memFun)(ARGS...), ARGS ...args)
Launch(FUN &&threadFunction, ARGS &&...args)
Launch && onOrphan(HOOK &&hook)
auto adaptedHook(FUN Policy::*, HOOK &&hook)
Helper to adapt a user provided hook to be usable as lifecycle hook.
void waitGracePeriod() noexcept
void handle_loose_thread()
called when destroying wrapper on still running thread
void detach_thread_from_wrapper()
allow to detach explicitly — independent from thread-function's state.
void launchThread(tuple< INVO... > &&invocation)
ThreadWrapper(string const &threadID)
bool invokedWithinThread() const
detect if the currently executing code runs within this thread
void handle_after_thread()
called immediately before end of thread
static string decorate_with_global_count(string const &)
Helper to create a suffix to the thread-ID with running count.
void handle_begin_thread()
called immediately at start of thread
Helpers for type detection, type rewriting and metaprogramming.