Library/Application: consolidate Monitor API and usage

This is Step-2 : change the API towards application

Notably all invocation variants to support member functions
or a reference to bool flags are retracted, since today a
λ-binding directly at usage site tends to be more readable.

The function names are harmonised with the C++ standard and
emergency shutdown in the Subsystem-Runner is rationalised.

The old thread-wrapper test is repurposed to demonstrate
the effectiveness of monitor based locking.
This commit is contained in:
Fischlurch 2023-10-15 20:42:55 +02:00
parent 73737f2aee
commit 685be1b039
29 changed files with 544 additions and 477 deletions

View file

@ -174,7 +174,7 @@ namespace advice {
void
manageAdviceData (PointOfAdvice* entry, DeleterFunc* how_to_delete)
{
Lock sync (this);
Lock sync{this};
adviceDataRegistry_.manage (entry, how_to_delete);
}
@ -196,14 +196,14 @@ namespace advice {
publishRequestBindingChange(PointOfAdvice & req,
HashVal previous_bindingKey)
{
Lock sync (this);
Lock sync{this};
index_.modifyRequest(previous_bindingKey, req);
}
void
registerRequest(PointOfAdvice & req)
{
Lock sync (this);
Lock sync{this};
index_.addRequest (req);
}
@ -212,7 +212,7 @@ namespace advice {
{
try
{
Lock sync (this);
Lock sync{this};
index_.removeRequest (req);
}
@ -227,7 +227,7 @@ namespace advice {
void
publishProvision (PointOfAdvice* newProvision, const PointOfAdvice* previousProvision)
{
Lock sync (this);
Lock sync{this};
if (!previousProvision && newProvision)
index_.addProvision (*newProvision);
@ -244,7 +244,7 @@ namespace advice {
void
discardSolutions (const PointOfAdvice* existingProvision)
{
Lock sync (this);
Lock sync{this};
if (existingProvision)
index_.removeProvision (*existingProvision);

View file

@ -118,7 +118,7 @@ namespace stage {
bool
start (lumiera::Option&, Subsys::SigTerm termNotification) override
{
Lock guard (this);
Lock guard{this};
if (facade)
return false; // already started
@ -159,7 +159,7 @@ namespace stage {
void
closeGuiModule ()
{
Lock guard (this);
Lock guard{this};
if (!facade)
{
WARN (guifacade, "Termination signal invoked, but GUI is currently closed. "

View file

@ -50,167 +50,162 @@
#include "lib/error.hpp"
#include "lib/util.hpp"
#include "lib/util-foreach.hpp"
#include "lib/format-string.hpp"
#include "common/subsys.hpp"
#include "lib/sync.hpp"
#include <functional>
#include <vector>
#include <string>
namespace lumiera {
using std::bind;
using std::function;
using std::placeholders::_1;
using lib::Sync;
using lib::RecursiveLock_Waitable;
using std::chrono_literals::operator ""s;
using std::vector;
using std::string;
using util::_Fmt;
using util::cStr;
using util::isnil;
using util::and_all;
using util::for_each;
using util::removeall;
using lib::Sync;
using lib::RecursiveLock_Waitable;
namespace {
/** limit waiting for subsystem shutdown in case of
* an emergency shutdown to max 2 seconds */
const uint EMERGENCYTIMEOUT = 2000;
function<bool(Subsys*)>
isRunning() {
return bind (&Subsys::isRunning, _1);
}
/** limited wait period for unwinding of remaining subsystems
* in case of an emergency shutdown, to avoid deadlock */
const auto EMERGENCY_STOP = 5s;
}
/*************************************************************************//**
* Implementation helper for managing execution of a collection of subsystems,
* which may depend on one another and execute in parallel. Properties of the
* subsystems are available through Subsys object refs, which act as handle.
* In this context, "Subsystem" is an \em abstraction and doesn't necessarily
* In this context, »Subsystem« is an _abstraction_ and doesn't necessarily
* correspond to a single component, interface or plugin. It may well be a
* complete layer of the application (e.g. the GUI).
*
* # Protocol of operation
* The SubsystemRunner is to be configured with a lumiera::Option object first.
* Then, primary subsystems are \link #maybeRun provided \endlink for eventual
* startup, which may depend on conditions defined by the subsystem. When
* a component is actually to be pulled up, all of its prerequisite subsystems
* shall be started in advance. Problems while starting may result in throwing
* an exception, which is \em not handled here and aborts the whole operation.
* On startup, a signal slot is reserved for each subsystem to notify the
* SubsystemRunner on termination. It is the liability of the subsystems to
* ensure this signal is activated regardless of what actually causes the
* termination; failure to do so may deadlock the SubsystemRunner.
* Then, primary subsystems are [provided](\ref SubsystemRunner::maybeRun) for
* eventual startup, which may depend on conditions defined by the subsystem.
* When it turns out (by investigating the options) that a Subsystem is actually
* to be pulled up, all of its prerequisite subsystems shall be started beforehand.
* Problems while starting may result in throwing an exception, which is _not handled_
* here and aborts the whole operation. On startup, a _callback signal slot_ is reserved
* for each subsystem to notify the SubsystemRunner on termination. It is the liability
* of the subsystems to ensure this callback functor is activated reliably, irrespective
* of what actually causes the termination; failure to do so may deadlock the whole System.
*
* Usually, the startup process is conducted from one (main) thread, which enters
* a blocking wait() after starting the subsystems. Awakened by some termination
* signal from one of the subsystems, termination of any remaining subsystems
* will be triggered. The #wait() function returns after shutdown of all subsystems,
* signalling an emergency exit (caused by an exception) with its return value.
* the [blocking wait](\ref SubsystemRunner::wait) after starting the subsystems.
* Awakened by some termination signal from one of the subsystems, termination of any
* remaining subsystems will be triggered. The #wait() function returns after shutdown
* of all subsystems, signalling an emergency situation with its return value. In this
* context, _emergency_ is defined by encountering an top-level exception in any
* Subsystem, reported by a non-empty error string in the #sigTerm handler.
* An _emergency_ thus jeopardises the ability to wind-down the all parts
* of the application reliably.
*
* @todo 2018 this component works well but could be (re)written in a cleaner way
* @todo 2018 this component works well but could be (re)written in a cleaner way ////////////////////////TICKET #1177
*
* @see lumiera::AppState
* @see lumiera::Subsys
* @see main.cpp
* @see main.cpp
*/
class SubsystemRunner
: public Sync<RecursiveLock_Waitable>
: public Sync<RecursiveLock_Waitable>
{
Option& opts_;
volatile bool emergency_;
vector<Subsys*> running_;
function<void(Subsys*)> start_,
stopIt_;
bool isEmergency() { return emergency_; }
bool allDead(){ return isnil (running_); }
public:
SubsystemRunner (Option& opts)
: opts_(opts)
, emergency_(false)
, start_(bind (&SubsystemRunner::triggerStartup, this,_1))
, stopIt_(bind (&Subsys::triggerShutdown, _1))
: opts_{opts}
, emergency_{false}
{ }
void
maybeRun (Subsys& susy)
{
Lock guard (this);
Lock guard{this};
if (!susy.isRunning() && susy.shouldStart (opts_))
triggerStartup (&susy);
}
void
shutdownAll ()
shutdownAll()
{
Lock guard (this);
for_each (running_, stopIt_);
Lock guard{this};
for_each (running_, [](Subsys* susy){ susy->triggerShutdown(); });
}
void
triggerEmergency (bool cond)
{
Lock guard (this);
{
Lock guard{this};
if (cond) emergency_= true;
}
bool
wait ()
wait()
{
Lock wait_blocking(this, &SubsystemRunner::allDead);
////////////////////////////////////////////////////////////OOO Emergency-Exit richtig implementieren
if (isEmergencyExit())
usleep(2*1000*1000);
return isEmergencyExit();
Lock blocking{this, [&]{ return allDead() or isEmergency(); }};
if (isEmergency())
blocking.wait_for (EMERGENCY_STOP, [&]{ return allDead(); });
// ...prevent deadlock on emergency by limiting shutdown wait
return isEmergency();
}
private:
bool isEmergencyExit () { return emergency_; }
void
triggerStartup (Subsys* susy)
{
auto isRunning = [](Subsys* susy){ return susy->isRunning(); };
auto triggerStart = [this](Subsys* susy){ triggerStartup(susy); };
auto termCallback = [this,susy]
(string* problem)
{
this->sigTerm (susy, problem);
};
REQUIRE (susy);
if (susy->isRunning()) return;
if (isRunning(susy)) return;
INFO (subsystem, "Triggering startup of subsystem \"%s\"", cStr(*susy));
for_each (susy->getPrerequisites(), start_);
bool started = susy->start (opts_, [this,susy]
(string* problem)
{
this->sigTerm (susy, problem);
});
for_each (susy->getPrerequisites(), triggerStart );
bool started = susy->start (opts_, termCallback);
if (started)
{
if (susy->isRunning())
if (isRunning(susy))
running_.push_back (susy); // now responsible for managing the started subsystem
else
throw error::Logic("Subsystem "+string(*susy)+" failed to start");
throw error::Logic(_Fmt{"Subsystem %s failed to start"} % *susy);
}
if (not and_all (susy->getPrerequisites(), isRunning() ))
if (not and_all (susy->getPrerequisites(), isRunning ))
{
susy->triggerShutdown();
throw error::State("Unable to start all prerequisites of Subsystem "+string(*susy));
throw error::State(_Fmt{"Unable to start all prerequisites of Subsystem %s"} % *susy);
} }
void
sigTerm (Subsys* susy, string* problem) ///< called from subsystem on termination
{
REQUIRE (susy);
Lock sync (this);
Lock sync{this};
triggerEmergency(not isnil (problem));
INFO (subsystem, "Subsystem '%s' terminated.", cStr(*susy));
WARN_IF (not isnil(problem), subsystem, "Irregular shutdown caused by: %s", cStr(*problem));
@ -218,24 +213,8 @@ namespace lumiera {
"without resetting running state", cStr(*susy));
removeall (running_, susy);
shutdownAll();
sync.notify();
sync.notify_one();
}
bool
allDead ()
{
if (isEmergencyExit())
{
// Lock sync(this);
// if (!sync.isTimedWait())
// sync.setTimeout(EMERGENCYTIMEOUT);
////////////////////////////////////////////////////////////OOO Emergency-Exit richtig implementieren
return true;
}
return isnil (running_); // end wait if no running subsystem left
}
};

View file

@ -106,7 +106,7 @@ namespace lib {
void
AllocationCluster::MemoryManager::reset (TypeInfo info)
{
Lock sync(this);
Lock sync{this};
if (0 < mem_.size()) purge();
type_ = info;
@ -121,7 +121,7 @@ namespace lib {
void
AllocationCluster::MemoryManager::purge()
{
Lock sync(this);
Lock sync{this};
REQUIRE (type_.killIt, "we need a deleter function");
REQUIRE (0 < type_.allocSize, "allocation size unknown");
@ -145,7 +145,7 @@ namespace lib {
inline void*
AllocationCluster::MemoryManager::allocate()
{
Lock sync(this);
Lock sync{this};
REQUIRE (0 < type_.allocSize);
REQUIRE (top_ <= mem_.size());
@ -165,7 +165,7 @@ namespace lib {
inline void
AllocationCluster::MemoryManager::commit (void* pendingAlloc)
{
Lock sync(this);
Lock sync{this};
REQUIRE (pendingAlloc);
ASSERT (top_ < mem_.size());

View file

@ -76,7 +76,7 @@ namespace lib {
throw error::Logic( "Unbound Functor fed to dispatcher CallQueue"
, error::LUMIERA_ERROR_BOTTOM_VALUE);
{
Lock sync(this);
Lock sync{this};
queue_.feed (move(op));
}
return *this;
@ -89,7 +89,7 @@ namespace lib {
{
Operation operate;
{
Lock sync(this);
Lock sync{this};
operate = move (*queue_);
++queue_;
}
@ -105,7 +105,7 @@ namespace lib {
size_t
size() const
{
Lock sync(this);
Lock sync{this};
return queue_.size();
}

View file

@ -80,7 +80,7 @@ namespace lib {
Literal
internedString (string && symbolString)
{
Lock sync(this);
Lock sync{this};
auto res = table_.insert (forward<string> (symbolString));
return res.first->c_str();
}

View file

@ -24,20 +24,28 @@
/** @file sync.hpp
** Object Monitor based synchronisation.
** The actual locking, signalling and waiting is implemented by delegating to the
** raw pthreads locking/sync calls. Rather, the purpose of the Sync baseclass is
** to support locking based on the <b>object monitor pattern</b>. This pattern
** describes a way of dealing with synchronisation known to play well with
** scoping, encapsulation and responsibility for a single purpose.
** a _mutex_ and for waiting also to a _condition variable_ as provided by the C++
** standard library. The purpose of the Sync baseclass is to provide a clear and simple
** everyday concurrency coordination based on the <b>object monitor pattern</b>. This
** pattern describes a way of dealing with synchronisation known to play well with
** scoping, encapsulation and responsibility for a single purpose. For performance
** critical code, other solutions (e.g. Atomics) might be preferable.
**
** # Usage
**
** A class becomes _lockable_ by inheriting from lib::Sync with the appropriate
** parametrisation. This causes any instance to inherit a monitor member (object),
** managing a mutex and (optionally) a condition variable for waiting. The actual
** synchronisation is achieved by placing a guard object as local (stack) variable
** into a given scope (typically a member function body). This guard object of
** class lib::Sync::Lock accesses the enclosing object's monitor and automatically
** manages the locking and unlocking; optionally it may also be used for waiting
** on a condition.
**
** maintaining a dedicated a mutex and (optionally) a condition variable for waiting.
** The actual synchronisation is achieved by placing a guard object as local (stack)
** variable into a given scope (typically a member function body). This guard object
** of class lib::Sync::Lock accesses the enclosing object's monitor and automatically
** manages the locking and unlocking; optionally it may also be used to perform a
** [wait-on-condition] the call to `Lock::wait(predicate)` will first check the
** predicate, and if it does not yield `true`, the thread will be put to sleep.
** It must be awakened from another thread by invoking `notify_one|all` and will
** then re-check the condition predicate. The `wait_for` variant allows to set
** a timeout to limit the sleep state, which implies however that the call may
** possibly return `false` in case the condition predicate is not (yet) fulfilled.
** @note
** - It is important to select a suitable parametrisation of the monitor.
** This is done by specifying one of the defined policy classes.
@ -48,15 +56,11 @@
** - The "this" pointer is fed to the ctor of the Lock guard object. Thus
** you may use any object's monitor as appropriate, especially in cases
** when adding the monitor to a given class may cause size problems.
** - For sake of completeness, this implementation provides the ability for
** timed waits. But please consider that in most cases there are better
** solutions for running an operation with given timeout by utilising the
** Lumiera scheduler. Thus use of timed waits is \b discouraged.
** - There is a special variant of the Lock guard called ClassLock, which
** can be used to lock based on a type, not an instance.
** - in DEBUG mode, the implementation includes NoBug resource tracking.
**
** @todo WIP-WIP 10/2023 switch from POSIX to C++14 ///////////////////////////////////////////////////////TICKET #1279 : also clean-up the Object-Monitor implementation
** [wait-on-condition]: https://en.cppreference.com/w/cpp/thread/condition_variable_any/wait
** @see mutex.h
** @see sync-locking-test.cpp
** @see sync-waiting-test.cpp
@ -226,6 +230,12 @@ namespace lib {
}
};
struct NoLocking
{
void lock() { /* boo */ }
void unlock() noexcept { /* hoo */ }
};
@ -345,6 +355,7 @@ namespace lib {
using Monitor = sync::Monitor<CONF>;
mutable Monitor objectMonitor_;
public:
static Monitor&
getMonitor(Sync const* forThis)
{
@ -353,9 +364,8 @@ namespace lib {
}
public:
/*****************************************//**
* scoped object to control the actual locking.
* scoped guard to control the actual locking.
*/
class Lock
: util::NonCopyable
@ -364,45 +374,37 @@ namespace lib {
public:
template<class X>
Lock(X* it) : mon_(getMonitor(it)){ mon_.lock(); }
Lock(X* it) : mon_{getMonitor(it)}{ mon_.lock(); }
~Lock() { mon_.unlock(); }
void notify() { mon_.notify_one(); }
void notifyAll() { mon_.notify_all(); }
void notify_one() { mon_.notify_one(); }
void notify_all() { mon_.notify_all(); }
template<typename C>
bool
wait (C&& cond, ulong timeout_ms=0) //////////////////////////////////////TICKET #1055 : accept std::chrono values here
template<class PRED>
void
wait (PRED&& predicate)
{
if (timeout_ms)
return mon_.wait_for (std::chrono::milliseconds(timeout_ms)
,std::forward<C> (cond));
else
{
mon_.wait (std::forward<C> (cond));
return true;
}
mon_.wait (std::forward<PRED>(predicate));
}
template<typename X>
template<class DUR, class PRED>
bool
wait (X& instance, bool (X::*predicate)(void), ulong timeout_ms=0) //////////////////////TICKET #1051 : enable use of lambdas
wait_for (DUR const& timeout, PRED&& predicate)
{
return wait([&]{ return (instance.*predicate)(); }, timeout_ms);
return mon_.wait_for (timeout, std::forward<PRED> (predicate));
}
/** convenience shortcut:
* Locks and immediately enters wait state,
* observing a condition defined as member function.
* @deprecated WARNING this function is not correct! ////////////////////////////TICKET #1051
* Lock is not released on error from within wait() /////TODO is actually fixed now; retain this API??
* Locks and immediately enters wait state on the given predicate
*/
template<class X>
Lock(X* it, bool (X::*method)(void))
template<class X, class PRED>
Lock(X* it, PRED&& predicate)
: mon_(getMonitor(it))
{
mon_.lock();
try { wait(*it,method); }
try {
mon_.wait (std::forward<PRED>(predicate));
}
catch(...)
{
mon_.unlock();
@ -413,7 +415,7 @@ namespace lib {
protected:
/** for creating a ClassLock */
Lock(Monitor& m)
: mon_(m)
: mon_{m}
{
mon_.lock();
}

View file

@ -157,7 +157,7 @@ namespace lib {
IxID typeID = TypedContext<TypedCounter>::ID<TY>::get();
if (size() < typeID)
{ // protect against concurrent slot allocations
Lock sync(this);
Lock sync{this};
if (size() < typeID)
counters_.resize (typeID);
}

View file

@ -122,7 +122,7 @@ namespace asset {
//////////////////////////////////////////////////////////TICKET #840 check validity of Ident Category
ID<KIND> asset_id (getID (idi));
DB::Lock guard(&registry);
DB::Lock guard{&registry};
//////////////////////////////////////////////////////////TICKET #840 handle duplicate Registrations
lib::P<KIND> smart_ptr (obj, &destroy);

View file

@ -151,7 +151,7 @@ namespace control {
void
track (Symbol cmdID, Command const& commandHandle)
{
Lock sync(this);
Lock sync{this};
REQUIRE (commandHandle);
if (contains (index_,cmdID) || contains(ridx_, &commandHandle))
@ -173,7 +173,7 @@ namespace control {
bool
remove (Symbol cmdID)
{
Lock sync(this);
Lock sync{this};
bool actually_remove = contains (index_,cmdID);
if (actually_remove)
@ -197,7 +197,7 @@ namespace control {
Command
queryIndex (Symbol cmdID)
{
Lock sync(this);
Lock sync{this};
return getValue_or_default (index_, cmdID, Command() );
} //if not found
@ -209,7 +209,7 @@ namespace control {
Symbol
findDefinition (Command const& cmdInstance) const
{
Lock sync(this);
Lock sync{this};
return getValue_or_default (ridx_, &cmdInstance, Symbol::BOTTOM );
} //used as Key

View file

@ -53,6 +53,7 @@
#include "vault/real-clock.hpp"
#include <functional>
#include <chrono>
@ -63,6 +64,7 @@ namespace control {
using lib::time::TimeVar;
using lib::time::Offset;
using lib::time::Duration;
using std::chrono::milliseconds;
using vault::RealClock;
namespace {
@ -206,14 +208,15 @@ namespace control {
return not isDying();
}
ulong /////////////////////////////////////////////TICKET #1056 : better return a std::chrono value here
milliseconds
getTimeout() const
{
if (not useTimeout())
return 0;
return milliseconds::zero();
else
return wakeTimeout_ms()
* (isDirty_ and not isWorking()? 1 : slowdownFactor());
return milliseconds{
wakeTimeout_ms()
* (isDirty_ and not isWorking()? 1 : slowdownFactor())};
}

View file

@ -163,7 +163,7 @@ namespace control {
init_.sync(); // done with setup; loop may run now....
INFO (session, "Steam-Dispatcher running...");
{
Lock sync(this); // open public session interface:
Lock sync{this}; // open public session interface:
commandService_.createInstance(*this);
}
}
@ -182,42 +182,41 @@ namespace control {
void
activateCommandProecssing()
{
Lock sync(this);
Lock sync{this};
looper_.enableProcessing(true);
INFO (command, "Session command processing activated.");
sync.notifyAll();
sync.notify_all();
}
void
deactivateCommandProecssing()
{
Lock sync(this);
Lock sync{this};
looper_.enableProcessing(false);
INFO (command, "Session command interface closed.");
sync.notifyAll();
sync.notify_all();
}
void
requestStop() noexcept
{
Lock sync(this);
Lock sync{this};
commandService_.shutdown(); // closes Session interface
looper_.triggerShutdown();
sync.notifyAll();
sync.notify_all();
}
void
awaitStateProcessed() const
{
Lock(unConst(this)).wait(unConst(*this), &DispatcherLoop::isStateSynched); ///////////////////////TICKET #1051 : support bool-λ and fix the correctness-error in the »convenience shortcut«
////////////////////////TICKET #1057 : const correctness on wait predicate
// wake-up typically by updateState()
Lock{this, [&]{ return isStateSynched(); }};
// wake-up typically by updateState()
}
size_t
size() const
{
Lock sync(this);
Lock sync{this};
return queue_.size();
}
@ -227,17 +226,17 @@ namespace control {
void
enqueue (Command&& cmd) override
{
Lock sync(this);
Lock sync{this};
queue_.feed (move (cmd));
sync.notifyAll();
sync.notify_all();
}
void
clear() override
{
Lock sync(this);
Lock sync{this};
queue_.clear();
sync.notifyAll();
sync.notify_all();
}
private:
@ -282,8 +281,8 @@ namespace control {
void
awaitAction() ///< at begin of loop body...
{
Lock(this).wait(looper_, &Looper::requireAction,
looper_.getTimeout());
Lock{this}.wait_for (looper_.getTimeout()
,[&]{ return looper_.requireAction(); });
}
void
@ -291,11 +290,11 @@ namespace control {
{
looper_.markStateProcessed();
if (looper_.isDisabled()) // otherwise wake-up would not be safe
Lock(this).notifyAll();
getMonitor(this).notify_all();
}
bool
isStateSynched()
isStateSynched() const
{
if (thread_.invokedWithinThread())
throw error::Fatal("Possible Deadlock. "
@ -310,7 +309,7 @@ namespace control {
{
Command cmd;
{
Lock sync(this);
Lock sync{this};
if (not queue_.empty())
cmd = queue_.pop();
}
@ -361,7 +360,7 @@ namespace control {
bool
SteamDispatcher::start (Subsys::SigTerm termNotification)
{
Lock sync(this);
Lock sync{this};
if (runningLoop_) return false;
runningLoop_ =
@ -389,7 +388,7 @@ namespace control {
void
SteamDispatcher::endRunningLoopState()
{
Lock sync(this);
Lock sync{this};
if (runningLoop_)
runningLoop_.reset(); // delete DispatcherLoop object
else
@ -407,7 +406,7 @@ namespace control {
bool
SteamDispatcher::isRunning()
{
Lock sync(this);
Lock sync{this};
return bool(runningLoop_);
}
@ -419,7 +418,7 @@ namespace control {
SteamDispatcher::requestStop() noexcept
{
try {
Lock sync(this);
Lock sync{this};
if (runningLoop_)
runningLoop_->requestStop();
}
@ -439,7 +438,7 @@ namespace control {
void
SteamDispatcher::activate()
{
Lock sync(this);
Lock sync{this};
active_ = true;
if (runningLoop_)
runningLoop_->activateCommandProecssing();
@ -455,7 +454,7 @@ namespace control {
void
SteamDispatcher::deactivate()
{
Lock sync(this);
Lock sync{this};
active_ = false;
if (runningLoop_)
runningLoop_->deactivateCommandProecssing();
@ -471,7 +470,7 @@ namespace control {
void
SteamDispatcher::awaitDeactivation()
{
Lock sync(this);
Lock sync{this};
if (runningLoop_)
runningLoop_->awaitStateProcessed();
}
@ -481,7 +480,7 @@ namespace control {
void
SteamDispatcher::clear()
{
Lock sync(this);
Lock sync{this};
if (not empty())
{
WARN (command, "DISCARDING pending Session commands.");
@ -494,7 +493,7 @@ namespace control {
bool
SteamDispatcher::empty() const
{
Lock sync(this);
Lock sync{this};
return not runningLoop_
or 0 == runningLoop_->size();
}

View file

@ -228,7 +228,7 @@ namespace session {
bool
SessManagerImpl::isUp()
{
Lock sync(this);
Lock sync{this};
return bool(pSess_); ///////////////////// TICKET #702 possible race, because this gets true way before the interface is up
}
@ -238,7 +238,7 @@ namespace session {
void
SessManagerImpl::clear()
{
Lock sync(this);
Lock sync{this};
pSess_->clear();
}
@ -251,7 +251,7 @@ namespace session {
void
SessManagerImpl::close()
{
Lock sync(this);
Lock sync{this};
if (isUp())
lifecycle_->shutDown();
pSess_.reset();
@ -266,7 +266,7 @@ namespace session {
void
SessManagerImpl::reset()
{
Lock sync(this);
Lock sync{this};
if (isUp())
lifecycle_->shutDown();
lifecycle_->pullUp();
@ -279,7 +279,7 @@ namespace session {
SessManagerImpl::load()
{
UNIMPLEMENTED ("load serialised session");
Lock sync(this);
Lock sync{this};
if (isUp())
lifecycle_->shutDown();
lifecycle_->pullUp();

View file

@ -71,7 +71,7 @@ namespace play {
bool
OutputDirector::connectUp()
{
Lock sync(this);
Lock sync{this};
REQUIRE (not shutdown_initiated_);
player_.createInstance();
@ -122,7 +122,7 @@ namespace play {
void
OutputDirector::bringDown (SigTerm completedSignal)
{
Lock sync(this);
Lock sync{this};
string problemLog;
if (not isOperational())
{

View file

@ -113,7 +113,7 @@ namespace play {
throw;
}
Lock sync(this);
Lock sync{this};
processes_.push_back (frontend); // keeping a weak-reference
return frontend;
}
@ -132,7 +132,7 @@ namespace play {
/////////////////////////////////////////////TICKET #867 : somehow ensure sane abort of all attached calculation efforts
delete dyingProcess;
Lock sync(this);
Lock sync{this};
remove_if (processes_, isDead);
}

View file

@ -72,7 +72,7 @@ namespace vault {
bool
checkRunningState () noexcept override
{
//Lock guard (*this);
//Lock guard{*this};
TODO ("implement detecting running state");
return false;
}

View file

@ -67,7 +67,7 @@ namespace vault {
bool
checkRunningState () noexcept override
{
//Lock guard (*this);
//Lock guard{*this};
TODO ("implement detecting running state");
return false;
}

View file

@ -69,7 +69,7 @@ namespace vault {
bool
checkRunningState () noexcept override
{
//Lock guard (*this);
//Lock guard{*this};
TODO ("implement detecting running state");
return false;
}

View file

@ -191,7 +191,7 @@ namespace test{
void
countConsumerCall (uint increment)
{
Lock sync(this); // NOTE: will be invoked from some random other thread
Lock sync{this}; // NOTE: will be invoked from some random other thread
consumerSum += increment;
}

View file

@ -38,6 +38,8 @@ namespace test {
namespace { // test fixture...
using Dur = std::chrono::duration<double, std::milli>;
/**
* @todo this value should be retrieved from configuration ////////////////////////////////TICKET #1052 : access application configuration
* @see Looper::establishWakeTimeout()
@ -45,22 +47,22 @@ namespace test {
const uint EXPECTED_BUILDER_DELAY_ms = 50;
bool
isFast (uint timeoutDelay_ms)
isFast (milliseconds timeoutDelay)
{
return timeoutDelay_ms < 1.2 * EXPECTED_BUILDER_DELAY_ms
and 0 < timeoutDelay_ms;
return timeoutDelay < Dur{1.2 * EXPECTED_BUILDER_DELAY_ms}
and 0ms < timeoutDelay;
}
bool
isSlow (uint timeoutDelay_ms)
isSlow (milliseconds timeoutDelay)
{
return timeoutDelay_ms >= 1.2 * EXPECTED_BUILDER_DELAY_ms;
return timeoutDelay >= Dur{1.2 * EXPECTED_BUILDER_DELAY_ms};
}
bool
isDisabled (uint timeoutDelay_ms)
isDisabled (milliseconds timeoutDelay)
{
return 0 == timeoutDelay_ms;
return 0ms == timeoutDelay;
}
@ -129,9 +131,9 @@ namespace test {
setup.has_commands_in_queue = true;
CHECK (looper.requireAction());
uint timeout = looper.getTimeout();
CHECK (10 < timeout, "configured idle timeout %2u to short", timeout);
CHECK (timeout < 800, "configured idle timeout %3u to long", timeout);
milliseconds timeout = looper.getTimeout();
CHECK (10ms < timeout, "configured idle timeout %2l to short", timeout.count());
CHECK (timeout < 800ms, "configured idle timeout %3l to long", timeout.count());
}

View file

@ -74,10 +74,10 @@ namespace test {
void
sync()
{
Lock sync(this);
Lock sync{this};
--latch_;
sync.wait(*this, &MonitorSync::allPassed);
sync.notifyAll();
sync.wait ([this]{ return allPassed(); });
sync.notify_all();
}
private:

View file

@ -87,7 +87,7 @@ namespace test {
};
for (auto& thread : threads)
thread.join(); // block until thread terminates
thread.join(); // block until thread terminates
CHECK (contended == NUM_THREADS * NUM_LOOP,
"ALARM: Lock failed, concurrent modification "

View file

@ -62,7 +62,7 @@ namespace test{
void
pause ()
{
Lock guard (this); // note recursive lock
Lock guard{this}; // note recursive lock
for ( uint i=0, lim=(rand() % MAX_PAUSE); i<lim; ++i)
;
@ -89,7 +89,7 @@ namespace test{
void
inc (uint newStep)
{
Lock guard (this);
Lock guard{this};
step_ = newStep;
incrementAll();
}
@ -97,7 +97,7 @@ namespace test{
bool
belowLimit ()
{
Lock guard (this);
Lock guard{this};
return cnt_[0] < MAX_SUM;
}

View file

@ -27,45 +27,51 @@
#include "lib/test/run.hpp"
#include "lib/thread.hpp"
#include "lib/sync.hpp"
#include "lib/symbol.hpp"
#include "lib/thread.hpp"
#include "lib/iter-explorer.hpp"
#include "lib/scoped-collection.hpp"
#include <functional>
using std::bind;
using test::Test;
using lib::explore;
using std::this_thread::yield;
using std::this_thread::sleep_for;
using std::chrono_literals::operator ""us;
namespace lib {
namespace test {
namespace test{
namespace { // private test classes and data...
const uint NUM_THREADS = 20;
const uint NUM_THREADS = 200;
const uint MAX_RAND_SUMMAND = 100;
/** Helper to verify a contended chain calculation */
template<class POLICY>
class Checker
: public lib::Sync<>
: public Sync<POLICY>
{
volatile ulong hot_sum_;
ulong control_sum_;
size_t hot_sum_{0};
size_t control_sum_{0};
using Lock = typename Sync<POLICY>::Lock;
public:
Checker() : hot_sum_(0), control_sum_(0) { }
bool
verify() ///< verify test values got handled and accounted
{
Lock guard{this};
return 0 < hot_sum_
&& control_sum_ == hot_sum_;
and control_sum_ == hot_sum_;
}
uint
createVal() ///< generating test values, remembering the control sum
{
uint val(rand() % MAX_RAND_SUMMAND);
uint val{rand() % MAX_RAND_SUMMAND};
control_sum_ += val;
return val;
}
@ -73,55 +79,31 @@ namespace lib {
void
addValues (uint a, uint b) ///< to be called concurrently
{
Lock guard(this);
Lock guard{this};
hot_sum_ *= 2;
usleep (200); // force preemption
sleep_for (200us); // force preemption
hot_sum_ += 2 * (a+b);
usleep (200);
sleep_for (200us);
hot_sum_ /= 2;
}
};
Checker checksum; ///< global variable used by multiple threads
struct TestThread
: Thread
{
TestThread()
: Thread{&TestThread::theOperation, checksum.createVal(), checksum.createVal()}
{ } // note the binding (functor object) is passed as anonymous temporary
void
theOperation (uint a, uint b) ///< the actual operation running in a separate thread
{
checksum.addValues (a,b);
}
};
} // (End) test classes and data....
}// (End) test classes and data....
/**********************************************************************//**
* @test use the Lumiera Vault to create some new threads, utilising the
* lumiera::Thread wrapper for binding to an arbitrary operation
* and passing the appropriate context.
*
* @see vault::Thread
* @see threads.h
/******************************************************************//**
* @test verify the object monitor provides locking and to prevent
* data corruption on concurrent modification of shared storage.
* - use a chained calculation with deliberate sleep state
* while holding onto an intermediary result
* - run this calculation contended by a huge number of threads
* - either use locking or no locking
* @see sync.happ
* @see thread.hpp
*/
class SyncLocking_test2 : public Test
{
@ -129,11 +111,31 @@ namespace lib {
virtual void
run (Arg)
{
TestThread instances[NUM_THREADS] SIDEEFFECT;
CHECK (can_calc_without_Error<NonrecursiveLock_NoWait>());
CHECK (can_calc_without_Error<RecursiveLock_NoWait>());
CHECK (not can_calc_without_Error<sync::NoLocking>());
}
template<class POLICY>
bool
can_calc_without_Error()
{
Checker<POLICY> checksum; // shared variable used by multiple threads
usleep (200000); // pause 200ms for the threads to terminate.....
lib::ScopedCollection<Thread> threads{NUM_THREADS};
for (uint i=1; i<=NUM_THREADS; ++i)
threads.emplace ([&checksum, // Note: added values prepared in main thread
a = checksum.createVal(),
b = checksum.createVal()]
{
checksum.addValues (a,b);
});
CHECK (checksum.verify());
while (explore(threads).has_any())
yield(); // wait for all threads to terminate
return checksum.verify();
}
};

View file

@ -33,6 +33,7 @@
using test::Test;
using std::chrono::system_clock;
using std::chrono::milliseconds;
namespace lib {
@ -40,7 +41,8 @@ namespace test{
namespace { // test parameters...
const uint WAIT_mSec = 20; ///< milliseconds to wait before timeout
const uint WAIT_mSec = 20; ///< milliseconds to wait before timeout
const milliseconds TIMEOUT{WAIT_mSec};
using CLOCK_SCALE = std::milli; // Results are in ms
using Dur = std::chrono::duration<double, CLOCK_SCALE>;
@ -71,12 +73,12 @@ namespace test{
virtual void
run (Arg)
{
Lock lock(this);
Lock lock{this};
auto start = system_clock::now();
auto salvation = []{ return false; };
bool fulfilled = lock.wait (salvation, WAIT_mSec);
bool fulfilled = lock.wait_for (TIMEOUT, salvation);
CHECK (not fulfilled); // condition not fulfilled, but timeout

View file

@ -31,89 +31,46 @@
#include "lib/thread.hpp"
#include "lib/sync.hpp"
#include <functional>
#include <atomic>
using test::Test;
using std::atomic_uint;
using std::atomic_bool;
using std::this_thread::sleep_for;
using std::chrono_literals::operator ""ms;
namespace lib {
namespace test{
namespace { // private test classes and data...
/** Interface defining the basic interaction pattern for this test */
class Token
{
public:
/** blocking concurrent operation */
virtual void getIt() =0;
/** start the notification chain */
virtual void provide (uint val) =0;
/** harvesting the result...*/
uint result () { return sum_; }
protected:
volatile uint sum_, input_;
virtual ~Token() {}
Token() : sum_(0), input_(0) {}
};
namespace { // test subject...
/** demonstrates how to wait on a simple boolean flag */
class SyncOnBool
: public Token,
public Sync<NonrecursiveLock_Waitable>
: public Sync<NonrecursiveLock_Waitable>
{
protected:
atomic_uint sum_{0}, input_{0};
atomic_bool got_new_data_{false};
public:
void getIt()
{
Lock(this).wait ([this]{ return bool(got_new_data_); });
Lock await{this, [&]{ return bool(got_new_data_); }};
sum_ += input_;
}
void provide (uint val)
{
Lock sync(this);
Lock sync{this};
input_ = val;
got_new_data_ = true;
sync.notifyAll();
}
};
/** this variant demonstrates how to wait on an condition
* defined in terms of a (bool) member function
*/
class SyncOnMemberPredicate
: public SyncOnBool
{
bool checkTheFlag() { return this->got_new_data_; }
public:
void getIt()
{
Lock await(this, &SyncOnMemberPredicate::checkTheFlag); /////////////////////TODO becomes obsolete with the API change
sum_ += input_;
sync.notify_all();
}
/** harvesting the result...*/
uint result () { return sum_; }
};
} // (End) test classes and data....
}//(End) test subject.
@ -124,11 +81,9 @@ namespace test{
/************************************************************************//**
* @test concurrent waiting and notification, implemented via object monitor.
* This test covers the second part of the monitor pattern, which builds upon
* the locking part, additionally using an embedded condition. We provide
* several pre-configured ways of specifying the condition to wait upon.
* - check a boolean flag
* - evaluate a member function as predicate
*
* the locking part, additionally using an embedded condition. Two interwoven
* threads are created, both blocked until a start value is given. Once awakened,
* each thread should add the start value to a common sum field.
* @see SyncLocking_test
* @see sync.hpp
*/
@ -138,43 +93,26 @@ namespace test{
virtual void
run (Arg)
{
SyncOnBool use_sync_var;
waitPingPong (use_sync_var);
SyncOnBool token;
SyncOnMemberPredicate use_member_pred;
waitPingPong (use_member_pred);
}
/**
* Helper actually performing the test:
* creates two threads and let them block and wait until a start value is given.
* When awakened, each thread should add the start value to a common sum field.
* @param tok object containing the monitor and condition to be tested.
*/
void
waitPingPong (Token& tok)
{
typedef ThreadJoinable<> Thread; //////////////////////////////////////WIP
Thread ping ("SyncWaiting ping", [&]{ return tok.getIt(); });
Thread pong ("SyncWaiting pong", [&]{ return tok.getIt(); });
ThreadJoinable ping ("SyncWaiting ping", [&]{ token.getIt(); });
ThreadJoinable pong ("SyncWaiting pong", [&]{ token.getIt(); });
CHECK (ping);
CHECK (pong);
CHECK (0 == tok.result());
CHECK (0 == token.result());
usleep (100000); // if the threads don't block correctly, they've missed their chance by now...
sleep_for (100ms); // if the threads don't block correctly, they've missed their chance by now...
// kick off the notification cascade...
uint val = (rand() % 1000);
tok.provide (val);
token.provide (val);
// wait for the two Threads to finish their handshake
pong.join();
ping.join();
CHECK (2*val == tok.result());
CHECK (2*val == token.result());
}
};

View file

@ -576,7 +576,7 @@ namespace test {
void
scheduleBorg (uint id)
{
Lock sync(this);
Lock sync{this};
borgChecksum_ += id;
sessionBorgs_.push(id);
}
@ -584,7 +584,7 @@ namespace test {
auto
dispatchBorgs()
{
Lock sync(this);
Lock sync{this};
return dischargeToSnapshot (sessionBorgs_);
}

View file

@ -357,13 +357,13 @@ namespace test {
void
mark (std::thread::id const& tID)
{
Lock guard(this);
Lock guard{this};
this->insert(tID);
}
operator size_t() const
{
Lock guard(this);
Lock guard{this};
return this->size();
}
}

View file

@ -66356,7 +66356,7 @@
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1696538243989" ID="ID_963020368" MODIFIED="1697212009165" TEXT="Objekt-Monitor (Wrapper)">
<linktarget COLOR="#e81e74" DESTINATION="ID_963020368" ENDARROW="Default" ENDINCLINATION="-1386;137;" ID="Arrow_ID_750207085" SOURCE="ID_1209350338" STARTARROW="None" STARTINCLINATION="-379;-555;"/>
<linktarget COLOR="#1e9fe8" DESTINATION="ID_963020368" ENDARROW="Default" ENDINCLINATION="-1386;137;" ID="Arrow_ID_750207085" SOURCE="ID_1209350338" STARTARROW="None" STARTINCLINATION="-379;-555;"/>
<icon BUILTIN="pencil"/>
<node CREATED="1696538320106" ID="ID_1371656828" MODIFIED="1696538327925" TEXT="Wrapper bestand schon bisher">
<node CREATED="1696538329153" ID="ID_23495962" MODIFIED="1696538341970" TEXT="war zun&#xe4;chst aufgebaut auf Christian&apos;s NoBug-Adapter"/>
@ -66365,7 +66365,7 @@
<icon BUILTIN="yes"/>
</node>
</node>
<node COLOR="#338800" CREATED="1696538432819" ID="ID_1257702273" MODIFIED="1697321899332" TEXT="Analyse der Semantik">
<node COLOR="#338800" CREATED="1696538432819" FOLDED="true" ID="ID_1257702273" MODIFIED="1697321899332" TEXT="Analyse der Semantik">
<icon BUILTIN="button_ok"/>
<node CREATED="1696538453264" ID="ID_1672358651" MODIFIED="1696538455260" TEXT="POSIX">
<node CREATED="1696538464327" ID="ID_1024694040" MODIFIED="1696538476389" TEXT="ich hatte schon einen Basis-Adapter dazwischen">
@ -66548,8 +66548,12 @@
<node CREATED="1697156077365" ID="ID_1535123758" MODIFIED="1697156103949" TEXT="Zus&#xe4;tzlich Erg&#xe4;nzung um eine TryLock-Variante (als optional&lt;Guard&gt;)"/>
</node>
</node>
<node CREATED="1697156128590" ID="ID_731556592" MODIFIED="1697156131743" TEXT="Abw&#xe4;gung">
<node CREATED="1697156137517" ID="ID_817522107" MODIFIED="1697156191121" TEXT="der &#xbb;transparente Switch&#xab; ist rasch und ohne Risiko umsetzbar">
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1697156128590" ID="ID_731556592" MODIFIED="1697385802949" TEXT="Abw&#xe4;gung">
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
<node CREATED="1697156137517" ID="ID_817522107" MODIFIED="1697385837580" TEXT="der &#xbb;transparente Switch&#xab; ist rasch und ohne Risiko umsetzbar">
<arrowlink COLOR="#58a8bf" DESTINATION="ID_1417792791" ENDARROW="Default" ENDINCLINATION="94;-287;" ID="Arrow_ID_1502905066" STARTARROW="None" STARTINCLINATION="-173;8;"/>
<icon BUILTIN="full-1"/>
<node CREATED="1697156194805" ID="ID_520707349" MODIFIED="1697156316185" TEXT="Ziel ist, den status-quo zu erhalten"/>
<node CREATED="1697156375349" ID="ID_854423215" MODIFIED="1697156397382" TEXT="erweiterte Analyse + Tests sind nicht notwendig"/>
<node CREATED="1697156317135" ID="ID_935065583" MODIFIED="1697156350020" TEXT="das wird erkauft durch eine exzessiv indirekte Code-Struktur"/>
@ -66579,7 +66583,9 @@
<node CREATED="1697156922980" ID="ID_1251565315" MODIFIED="1697156937622" TEXT="das Ergebnis stellt aber keine strukturelle Verschlechterung dar"/>
<node CREATED="1697156941858" ID="ID_933669206" MODIFIED="1697156948146" TEXT="...und k&#xf6;nnte daher ein Zwischenschritt sein"/>
</node>
<node CREATED="1697156852566" ID="ID_1056176020" MODIFIED="1697156881277" TEXT="die &#xbb;strukturelle Verbesserung&#xab; stellt l&#xe4;ngerfristig das Minimum an Code-Qualit&#xe4;t dar">
<node CREATED="1697156852566" ID="ID_1056176020" MODIFIED="1697385897702" TEXT="die &#xbb;strukturelle Verbesserung&#xab; stellt l&#xe4;ngerfristig das Minimum an Code-Qualit&#xe4;t dar">
<arrowlink COLOR="#18889d" DESTINATION="ID_785406259" ENDARROW="Default" ENDINCLINATION="22;-279;" ID="Arrow_ID_1406241214" STARTARROW="None" STARTINCLINATION="-290;10;"/>
<icon BUILTIN="full-2"/>
<node CREATED="1697156959663" ID="ID_1687873684" MODIFIED="1697156975190" TEXT="da klar ist, da&#xdf; nur der Monitor verwendet werden soll..."/>
<node CREATED="1697156976195" ID="ID_681854744" MODIFIED="1697156985008" TEXT="deshalb kann auch alles Andere zur&#xfc;ckgebaut werden"/>
<node CREATED="1697157070044" ID="ID_1501146985" MODIFIED="1697157223059" TEXT="die unique_lock-Instanz ist zugleich Verbesserung und zus&#xe4;tzlicher Ballast">
@ -66595,7 +66601,8 @@
<node CREATED="1697157236623" ID="ID_1796494876" MODIFIED="1697157269817" TEXT="die Implementierung im Monitor m&#xfc;&#xdf;te schrittweise aufgebaut/konsolidiert werden"/>
<node CREATED="1697157270541" ID="ID_1316555147" MODIFIED="1697157286077" TEXT="dazu sollte vorher f&#xfc;r ausreichende Test-Coverage gesorgt sein"/>
</node>
<node CREATED="1697157349262" ID="ID_871141135" MODIFIED="1697157367972" TEXT="das &#xbb;Monitor-Refactoring&#xab; entspricht meinem eigenen Qualit&#xe4;ts-Anspruch">
<node CREATED="1697157349262" ID="ID_871141135" MODIFIED="1697157349262" TEXT="das &#xbb;Monitor-Refactoring&#xab; entspricht meinem eigenen Qualit&#xe4;ts-Anspruch">
<icon BUILTIN="full-3"/>
<node CREATED="1697157372112" ID="ID_247839273" MODIFIED="1697157389225" TEXT="das bedeutet: l&#xe4;ngerfristig sollte das das Ziel sein"/>
<node CREATED="1697157390189" ID="ID_1494264417" MODIFIED="1697157417062" TEXT="Nachteil: es ist ein Privat-Konzept und theoretisch nicht untersucht"/>
<node CREATED="1697157432440" ID="ID_30899784" MODIFIED="1697157455160" TEXT="es w&#xfc;rde das Ballast-Problem der mittleren Variante beheben"/>
@ -66616,13 +66623,16 @@
</body>
</html></richcontent>
</node>
<node CREATED="1697157736647" ID="ID_1786481655" MODIFIED="1697157768097" TEXT="da ich unter Zeitdruck stehe, ist es denkbar, zun&#xe4;chst nur die erste Stufe umzusetzen"/>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1697157736647" ID="ID_1786481655" MODIFIED="1697385915735" TEXT="da ich unter Zeitdruck stehe, ist es denkbar, zun&#xe4;chst nur die erste Stufe umzusetzen">
<icon BUILTIN="hourglass"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696538492114" ID="ID_1214186481" MODIFIED="1696538497123" TEXT="Umarbeiten">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1697208267170" ID="ID_1417792791" MODIFIED="1697321886529" TEXT="Stufe-1">
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696538492114" ID="ID_1214186481" MODIFIED="1697385988338" TEXT="Umarbeiten">
<icon BUILTIN="yes"/>
<node COLOR="#338800" CREATED="1697208267170" FOLDED="true" ID="ID_1417792791" MODIFIED="1697385829109" TEXT="Stufe-1">
<linktarget COLOR="#58a8bf" DESTINATION="ID_1417792791" ENDARROW="Default" ENDINCLINATION="94;-287;" ID="Arrow_ID_1502905066" SOURCE="ID_817522107" STARTARROW="None" STARTINCLINATION="-173;8;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1697211709960" ID="ID_1334084058" MODIFIED="1697211722231" TEXT="mutex, shared_mutex und condition_var_any einf&#xfc;hren"/>
<node CREATED="1697212577546" ID="ID_701908821" MODIFIED="1697212604297" TEXT="elementare Wait-Logik in wrapped_condition nachbauen">
@ -66635,8 +66645,8 @@
<node CREATED="1697212978323" ID="ID_1878302471" MODIFIED="1697213004811" TEXT="also sollte den &#xbb;timeout&#xab; sofort modernisieren">
<node CREATED="1697226451516" ID="ID_1234718286" MODIFIED="1697226471469" TEXT="erst mal auf Millisekunden-Parameter, der 0 sein kann"/>
<node CREATED="1697226473433" ID="ID_1085819281" MODIFIED="1697226495115" TEXT="brauche keine Klasse Timeout mehr, die einen Timeout fest speichert"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697226910607" ID="ID_1996109798" MODIFIED="1697226924118" TEXT="bisher gab es das Konzept isTimedWait()">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#5b280f" CREATED="1697226910607" ID="ID_1996109798" MODIFIED="1697375725185" TEXT="bisher gab es das Konzept isTimedWait()">
<icon BUILTIN="button_cancel"/>
<node CREATED="1697227170044" ID="ID_1914088992" MODIFIED="1697227366621" TEXT="der Subsystem-Runner verwendet das (einzige Verwendung)"/>
<node CREATED="1697227176603" ID="ID_1461108141" MODIFIED="1697227196532" TEXT="er kann im Emergency-Fall nachtr&#xe4;glich ein Timeout setzen"/>
<node CREATED="1697227368355" ID="ID_8720299" MODIFIED="1697227492130" TEXT="vermeidet Deadlock mit nur einem Thread">
@ -66652,9 +66662,9 @@
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1697227493003" ID="ID_1899195103" MODIFIED="1697227520087" TEXT="erscheint mir halbgar">
<icon BUILTIN="smiley-angry"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697229575552" ID="ID_756306663" MODIFIED="1697232150319" TEXT="saubere L&#xf6;sung">
<arrowlink COLOR="#4b4593" DESTINATION="ID_1987547541" ENDARROW="Default" ENDINCLINATION="-595;-40;" ID="Arrow_ID_1122128450" STARTARROW="None" STARTINCLINATION="-613;91;"/>
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1697229575552" ID="ID_756306663" MODIFIED="1697375743316" TEXT="saubere L&#xf6;sung">
<arrowlink COLOR="#456a93" DESTINATION="ID_1987547541" ENDARROW="Default" ENDINCLINATION="-595;-40;" ID="Arrow_ID_1122128450" STARTARROW="None" STARTINCLINATION="-831;116;"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
@ -66680,6 +66690,7 @@
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1697238392317" ID="ID_785406259" MODIFIED="1697321911701" TEXT="Stufe-2">
<linktarget COLOR="#18889d" DESTINATION="ID_785406259" ENDARROW="Default" ENDINCLINATION="22;-279;" ID="Arrow_ID_1406241214" SOURCE="ID_1056176020" STARTARROW="None" STARTINCLINATION="-290;10;"/>
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1697315816914" ID="ID_1924043938" MODIFIED="1697315839198" TEXT="Implementierung in eine einzige Policy-Klasse">
<icon BUILTIN="button_ok"/>
@ -66696,8 +66707,8 @@
<node CREATED="1697318237762" ID="ID_178110028" MODIFIED="1697318254517" TEXT="und die Trennung ist ebenfalls vorzuzuziehen"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1697318278751" ID="ID_986327606" MODIFIED="1697321837879" TEXT="wait-API vereinheitlichen">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1697318278751" ID="ID_986327606" MODIFIED="1697385688333" TEXT="wait-API vereinheitlichen">
<icon BUILTIN="button_ok"/>
<node CREATED="1697318295168" ID="ID_1779444313" MODIFIED="1697321848775" TEXT="das Timeout-Feature wird (wie erwartet) nur selten genutzt">
<richcontent TYPE="NOTE"><html>
<head>
@ -66716,15 +66727,15 @@
</li>
</ul>
</body>
</html>
</richcontent>
</html></richcontent>
<arrowlink COLOR="#6879a1" DESTINATION="ID_620668033" ENDARROW="Default" ENDINCLINATION="8;-31;" ID="Arrow_ID_542802268" STARTARROW="None" STARTINCLINATION="-148;7;"/>
</node>
<node COLOR="#338800" CREATED="1697318385528" ID="ID_1149590819" MODIFIED="1697318406151" TEXT="den nachtr&#xe4;glich setzbaren Timeout schaffe ich ab">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697318411673" ID="ID_1823152866" MODIFIED="1697321858569" TEXT="besserer Funktor-Support">
<node COLOR="#435e98" CREATED="1697318411673" FOLDED="true" ID="ID_1823152866" MODIFIED="1697385716288" TEXT="besserer Funktor-Support">
<icon BUILTIN="yes"/>
<icon BUILTIN="button_cancel"/>
<node CREATED="1697319813178" ID="ID_939382602" MODIFIED="1697319816230" TEXT="F&#xe4;lle">
<node CREATED="1697318513548" ID="ID_1134079993" MODIFIED="1697318618743" TEXT="allgemeiner Funktor bool(void)">
<node CREATED="1697318602298" ID="ID_1305749510" MODIFIED="1697318609292" TEXT="das ist der Haupt-Eingang"/>
@ -66732,7 +66743,7 @@
</node>
<node CREATED="1697318499319" ID="ID_1385588809" MODIFIED="1697318512954" TEXT="Member-Funktion des Monitor-Tr&#xe4;gers">
<node CREATED="1697318580841" ID="ID_1410594297" MODIFIED="1697318588414" TEXT="kann nur auf dem Guard realisiert werden"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697323173068" ID="ID_1950494758" MODIFIED="1697327262001" TEXT="Problem: der this-Pointer ist nur im Lock-ctor bekannt">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1697323173068" ID="ID_1950494758" MODIFIED="1697370139917" TEXT="Problem: der this-Pointer ist nur im Lock-ctor bekannt">
<arrowlink COLOR="#b16c50" DESTINATION="ID_420557101" ENDARROW="Default" ENDINCLINATION="667;0;" ID="Arrow_ID_1731288409" STARTARROW="None" STARTINCLINATION="172;9;"/>
<icon BUILTIN="messagebox_warning"/>
</node>
@ -66750,8 +66761,7 @@
Hier gibt es zwar eine L&#252;cke, n&#228;mlich die const&amp; auf einen rvalue &#8212; aber das hier ist keine general-purpose-Library!
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1697320296110" ID="ID_393798254" MODIFIED="1697320326400" TEXT="Hauptproblem ist, das kompakt im Code darzustellen">
<icon BUILTIN="messagebox_warning"/>
@ -66769,8 +66779,7 @@
also entweder ganz oben oder ganz unten, und ansonsten nur noch einen Template-Parameter durchgeben
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="yes"/>
</node>
<node COLOR="#5b280f" CREATED="1697319863019" ID="ID_122504390" MODIFIED="1697327099006" TEXT="wegen Member-Funktion: mu&#xdf; im Guard behandelt werden">
@ -66789,8 +66798,7 @@
man mu&#223; nicht speziell auf den Typ des Tr&#228;gers abstellen; vielmehr kann man dann einen static-cast nachschalten, und der scheitert dann halt gegebenfalls beim Bauen. Das habe ich grade eben genauso beim neuen Thread-Wrapper gemacht, und es hat sich bisher gut bew&#228;hrt. Spezielle static-asserts sind dann gar nicht notwendig
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
</node>
<node COLOR="#435e98" CREATED="1697325938478" ID="ID_230563569" MODIFIED="1697326972528" TEXT="Zweifel: ist es dann &#xfc;berhaupt sinnvoll, Member-Pr&#xe4;dikate speziell zu unterst&#xfc;tzen?">
@ -66809,8 +66817,7 @@
man h&#228;tte dann also zwei verschiedene APIs f&#252;r <i>essentiell das Gleiche</i>
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1697326681404" ID="ID_88758521" MODIFIED="1697326701517" TEXT="andererseits ist durch die Lambdas eine generische L&#xf6;sung gegeben"/>
<node CREATED="1697326743932" ID="ID_956630359" MODIFIED="1697326921888" TEXT="...und diese ist nahezu genauso kompakt">
@ -66824,7 +66831,7 @@
<icon BUILTIN="yes"/>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1697327466147" ID="ID_893621038" MODIFIED="1697327486730" TEXT="dann wohl doch besser ganz unten die Spezalbehandlung f&#xfc;r bool-Flags?">
<node COLOR="#435e98" CREATED="1697327466147" ID="ID_893621038" MODIFIED="1697370007455" TEXT="dann wohl doch besser ganz unten die Spezalbehandlung f&#xfc;r bool-Flags?">
<icon BUILTIN="help"/>
<node CREATED="1697327490408" ID="ID_608568247" MODIFIED="1697327514952" TEXT="zumindest ist die Policy ein besserer Ort f&#xfc;r solche technischen Spezialit&#xe4;ten"/>
<node CREATED="1697327515500" ID="ID_1897397765" MODIFIED="1697327536325" TEXT="andererseits ist es dann &#xfc;berhaupt nicht mehr offensichtlich, da&#xdf; hier Magie passiert"/>
@ -66846,25 +66853,39 @@
&#955;-Notation ist inzwischen allgemein bekannt, und hat den Vorteil, da&#223; das Binding nahe am verwendeten Code liegt. Das gilt ganz besonders auch f&#252;r bool-Flags, und zudem m&#252;ssen wir uns dann nicht mehr mit Konvertierungen, volatile und Atomics herumschlagen
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
</node>
</node>
<node COLOR="#435e98" CREATED="1697370016112" ID="ID_939950597" MODIFIED="1697370131589">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<u>Fazit</u>: Nein &#8212; denn &#955; <i>sind bereits </i>der bessere &#8222;Support&#8220;
</p>
</body>
</html></richcontent>
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="forward"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1697320502329" ID="ID_195583180" MODIFIED="1697329841076" TEXT="Umbau">
<icon BUILTIN="pencil"/>
</node>
<node COLOR="#338800" CREATED="1697320502329" ID="ID_195583180" MODIFIED="1697385697483" TEXT="Umbau">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1697320475144" ID="ID_1616210437" MODIFIED="1697329834862" TEXT="Anpassungen nur bis in den Lock-Guard treiben">
<icon BUILTIN="full-1"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697320520036" ID="ID_304531035" MODIFIED="1697320544119" TEXT="Lock-Guard-API umbauen">
<node COLOR="#435e98" CREATED="1697320520036" ID="ID_304531035" MODIFIED="1697385534795" TEXT="Lock-Guard-API umbauen">
<icon BUILTIN="full-2"/>
</node>
</node>
</node>
<node CREATED="1697317281147" ID="ID_1588035403" MODIFIED="1697317292949" TEXT="API-Anpassungen Codebasis">
<node COLOR="#338800" CREATED="1697317281147" ID="ID_1588035403" MODIFIED="1697385681007" TEXT="API-Anpassungen Codebasis">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697320909394" ID="ID_1421524615" MODIFIED="1697320924162" TEXT="Darstellung der Condition">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1697321092943" ID="ID_719498386" MODIFIED="1697321100123" TEXT="Tickets">
@ -66875,16 +66896,20 @@
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697321013532" ID="ID_1169031361" MODIFIED="1697321091020" TEXT="#1051 allow lambdas for conditional wait (object monitor)">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697382313627" ID="ID_882837775" MODIFIED="1697382327650" TEXT="#1056 integrate wait / object-Monitor with std::chrono">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697321077876" ID="ID_1989704229" MODIFIED="1697321091020" TEXT="#994 integrate lambdas into function signature helpers">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697321125783" ID="ID_1918158334" MODIFIED="1697321155131" TEXT="erst mal nur das API im Lock-Guard damit reproduzieren">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1697321125783" ID="ID_1918158334" MODIFIED="1697385539816" TEXT="erst mal nur das API im Lock-Guard damit reproduzieren">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697321155723" ID="ID_1441525836" MODIFIED="1697321170393" TEXT="dann alle Verwendungen auf Modernisierungs-Potential pr&#xfc;fen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1697321155723" ID="ID_1441525836" MODIFIED="1697385542831" TEXT="dann alle Verwendungen auf Modernisierungs-Potential pr&#xfc;fen">
<icon BUILTIN="button_ok"/>
<node CREATED="1697326991042" ID="ID_163598257" MODIFIED="1697327008100" TEXT="alle Member-Pr&#xe4;dikate durch &#x3bb; ersetzen"/>
<node CREATED="1697369952877" ID="ID_599746501" MODIFIED="1697369991005" TEXT="einige notify_* k&#xf6;nnen ohne Lock operieren"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697321173920" ID="ID_599504048" MODIFIED="1697321323733" TEXT="Tickets dokumentieren und schlie&#xdf;en">
<richcontent TYPE="NOTE"><html>
@ -66896,14 +66921,13 @@
Im Besonderen #994 kann <i>nun wirklich langsam zugemacht werden! </i>Das schiebe ich nun schon so lange &#190; fertig vor mir her ... und es ist klar da&#223; ich den letzten Schritt (TYPES&lt;TY....&gt;) noch l&#228;nger vor mir her schiebe, wiewohl das eigentliche Problem effetiv bereits seit 2017 gel&#246;st ist
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="flag-yellow"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697317300096" ID="ID_169404073" MODIFIED="1697317304360" TEXT="direct-wait">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1697317305951" ID="ID_59576653" MODIFIED="1697317610834">
<node COLOR="#338800" CREATED="1697317300096" ID="ID_169404073" MODIFIED="1697385550127" TEXT="direct-wait">
<icon BUILTIN="button_ok"/>
<node CREATED="1697317305951" ID="ID_59576653" MODIFIED="1697386058818">
<richcontent TYPE="NODE"><html>
<head>
@ -66913,15 +66937,14 @@
hier hatte ich einen &#187;convenience-shortcut&#171; &#8212; und der <b><font color="#ae1010">ist broken</font></b>
</p>
</body>
</html>
</richcontent>
<arrowlink COLOR="#cb5590" DESTINATION="ID_276811059" ENDARROW="Default" ENDINCLINATION="-1328;-99;" ID="Arrow_ID_707193075" STARTARROW="None" STARTINCLINATION="-1717;72;"/>
</html></richcontent>
<arrowlink COLOR="#555dcb" DESTINATION="ID_276811059" ENDARROW="Default" ENDINCLINATION="-1328;-99;" ID="Arrow_ID_707193075" STARTARROW="None" STARTINCLINATION="-1717;72;"/>
<icon BUILTIN="messagebox_warning"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697317397853" ID="ID_1226608020" MODIFIED="1697317440595" TEXT="Ersatz: anonyme-Instanz">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697317413302" ID="ID_973377416" MODIFIED="1697317439510" TEXT="setzt besseren Support f&#xfc;r Member-Fun vorraus">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#5b280f" CREATED="1697317397853" ID="ID_1226608020" MODIFIED="1697369759666" TEXT="Ersatz: anonyme-Instanz">
<icon BUILTIN="button_cancel"/>
<node COLOR="#5b280f" CREATED="1697317413302" ID="ID_973377416" MODIFIED="1697369715879" TEXT="setzt besseren Support f&#xfc;r Member-Fun vorraus">
<icon BUILTIN="button_cancel"/>
<node CREATED="1697323263283" ID="ID_420557101" MODIFIED="1697327252114" TEXT="geht nur bedingt">
<richcontent TYPE="NOTE"><html>
<head>
@ -66932,10 +66955,9 @@
hab dummerweise den this-Ptr nicht mehr an dem Punkt; und das will ich auch nicht &#228;ndern &#8212; sonst hab ich in jeder dieser delegierenden Funktionen das getMonitor(this), und es ist auch inhaltlich nicht besonders pr&#228;zise, schlie&#223;lich arbeitet der Guard auf dem Monitor (siehe ClassLock)
</p>
</body>
</html>
</richcontent>
<linktarget COLOR="#9f5f73" DESTINATION="ID_420557101" ENDARROW="None" ENDINCLINATION="231;-36;" ID="Arrow_ID_1797357140" SOURCE="ID_28762827" STARTARROW="Default" STARTINCLINATION="-262;11;"/>
</html></richcontent>
<linktarget COLOR="#b16c50" DESTINATION="ID_420557101" ENDARROW="Default" ENDINCLINATION="667;0;" ID="Arrow_ID_1731288409" SOURCE="ID_1950494758" STARTARROW="None" STARTINCLINATION="172;9;"/>
<linktarget COLOR="#9f5f73" DESTINATION="ID_420557101" ENDARROW="None" ENDINCLINATION="231;-36;" ID="Arrow_ID_1797357140" SOURCE="ID_28762827" STARTARROW="Default" STARTINCLINATION="-262;11;"/>
<icon BUILTIN="stop-sign"/>
</node>
<node COLOR="#5b280f" CREATED="1697323594831" ID="ID_779865512" MODIFIED="1697324219364" TEXT="ich k&#xf6;nnte was GRAUSAMES tun....">
@ -66945,23 +66967,22 @@
<icon BUILTIN="smiley-oh"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1697323756673" ID="ID_1871015044" MODIFIED="1697324176249" TEXT="das w&#xe4;re sogar einigerma&#xdf;en sicher">
<richcontent TYPE="NOTE">&lt;html&gt;
&lt;head&gt;
<richcontent TYPE="NOTE"><html>
<head>
&lt;/head&gt;
&lt;body&gt;
&lt;p&gt;
...und zwar wegen der Typedef &amp;quot;Monitor&amp;quot;, die nur im Scope von Sync&amp;lt;CONF&amp;gt;
definiert ist &amp;#8212; das geht gut, SOLANGE niemand das Layout der Klasse Sync
&amp;#228;ndert, niemand &amp;#8222;aus Versehen&amp;#8220; eine VTable einf&amp;#252;hrt, und solange niemand
</head>
<body>
<p>
...und zwar wegen der Typedef &quot;Monitor&quot;, die nur im Scope von Sync&lt;CONF&gt;
definiert ist &#8212; das geht gut, SOLANGE niemand das Layout der Klasse Sync
&#228;ndert, niemand &#8222;aus Versehen&#8220; eine VTable einf&#252;hrt, und solange niemand
den Typ Monitor abgreift, woanders instantiiert und dann diese Referenz
&amp;#252;ber eine von Lock abgeleitete Klasse in die Referenz einspielt. &lt;b&gt;&lt;font color=&quot;#ea1b82&quot;&gt;TJA&lt;/font&gt;&lt;/b&gt;&amp;#160;
&amp;#9785; diesen &amp;#8222;Jemand&amp;#8220; gibt es bereits: SyncClasslock &lt;font color=&quot;#ad0000&quot;&gt;&amp;#55357;&amp;#56817;&lt;/font&gt;
&lt;/p&gt;
&lt;/body&gt;
&lt;/html&gt;
</richcontent>
&#252;ber eine von Lock abgeleitete Klasse in die Referenz einspielt. <b><font color="#ea1b82">TJA</font></b>&#160;
&#9785; diesen &#8222;Jemand&#8220; gibt es bereits: SyncClasslock <font color="#ad0000">&#55357;&#56817;</font>
</p>
</body>
</html></richcontent>
<icon BUILTIN="closed"/>
</node>
<node CREATED="1697324181717" ID="ID_1476992683" MODIFIED="1697324227340" TEXT="Fazit: anst&#xe4;ndige Leute und so &#x2014; und au&#xdf;erdem w&#xe4;re es gef&#xe4;hrlich">
@ -66982,10 +67003,22 @@
und zwar, weil eine solche anonyme Instanz den umschlie&#223;enden Scope nicht sch&#252;tzt; sie sieht aber syntaktisch genauso aus wie ein wirksamer Scope-Guard
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="stop-sign"/>
</node>
<node CREATED="1697369732182" ID="ID_1980534053" MODIFIED="1697369920976" TEXT="Beschlu&#xdf;: die M&#xf6;glichkei bleibt bestehen, wird aber nicht verwendet">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...vielmehr wird das Problem tats&#228;chlich gefixt, durch einen try-catch-Block; die spezielle Konstruktor-Variante bleibt damit erhalten, aber wir bieten generell keinen Support mehr f&#252;r Member-Funktionen, da dies nur f&#252;r den Konstruktor m&#246;glich w&#228;re, aber nich f&#252;r die frei stehende wait()-Variante. Ohnehin werden nun Lambdas bevorzugt, weil sie meist am Ort der Verwendung definiert werden und damit besser selbsterkl&#228;rend sind...
</p>
</body>
</html></richcontent>
<icon BUILTIN="forward"/>
</node>
</node>
<node COLOR="#338800" CREATED="1697318875030" ID="ID_1198984970" MODIFIED="1697329903095" TEXT="2.Alternative: den convenience-shortcut intern reparieren">
<icon BUILTIN="button_ok"/>
@ -66996,16 +67029,18 @@
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697319081650" ID="ID_1686143008" MODIFIED="1697319089823" TEXT="alle Verwendungen explizit durchpr&#xfc;fen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1697319081650" ID="ID_1686143008" MODIFIED="1697385547988" TEXT="alle Verwendungen explizit durchpr&#xfc;fen">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node CREATED="1697317628925" ID="ID_620668033" MODIFIED="1697321848776" TEXT="wait-timeout">
<node COLOR="#338800" CREATED="1697317628925" ID="ID_620668033" MODIFIED="1697385554584" TEXT="wait-timeout">
<linktarget COLOR="#6879a1" DESTINATION="ID_620668033" ENDARROW="Default" ENDINCLINATION="8;-31;" ID="Arrow_ID_542802268" SOURCE="ID_1779444313" STARTARROW="None" STARTINCLINATION="-148;7;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1697317643443" ID="ID_1921626506" MODIFIED="1697317648474" TEXT="Subsystem-Runner"/>
<node CREATED="1697317651618" ID="ID_694175448" MODIFIED="1697317655678" TEXT="Steam-Dispatcher"/>
</node>
<node CREATED="1697318178258" ID="ID_1033097807" MODIFIED="1697318198652" TEXT="notify_one|all">
<node COLOR="#338800" CREATED="1697318178258" ID="ID_1033097807" MODIFIED="1697385557081" TEXT="notify_one|all">
<icon BUILTIN="button_ok"/>
<node CREATED="1697319530923" ID="ID_914687428" MODIFIED="1697319578775" TEXT="sollte ohne Lock aufrufbar sein">
<richcontent TYPE="NOTE"><html>
<head>
@ -67016,12 +67051,32 @@
...rein konzeptionell ist es n&#228;mlich nicht notwendig, das Lock zu erlangen; aber unser bisheriges API hat dazu gezwungen. Nicht schlimm, aber auch nicht sch&#246;n
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1697319626249" ID="ID_1229703089" MODIFIED="1697319643061" TEXT="static Sync::getMonitor(this) kann man verwenden">
<node COLOR="#435e98" CREATED="1697319626249" ID="ID_1229703089" MODIFIED="1697385605448" TEXT="static Sync::getMonitor(this) kann man verwenden">
<icon BUILTIN="idea"/>
<node CREATED="1697319680566" ID="ID_875413808" MODIFIED="1697319698527" TEXT="das &quot;this&quot; ist hier eine ungl&#xfc;ckliche Konsequenz des Monitor-Patterns"/>
<node CREATED="1697319733263" ID="ID_1982854355" MODIFIED="1697319793219" TEXT="...denn es geht um andere Threads, nicht um die Instanz"/>
<node CREATED="1697385563278" ID="ID_1846180648" MODIFIED="1697385592633">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
mu&#223; dazu getMonitor() <b><font color="#58312c">public</font></b>&#160;machen
</p>
</body>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
</node>
<node CREATED="1697385611400" ID="ID_1181983883" MODIFIED="1697385630226" TEXT="es gibt eine sinnvolle Verwendung im Steam-Dispatcher">
<icon BUILTIN="info"/>
<node CREATED="1697385640834" ID="ID_1277267659" MODIFIED="1697385652405" TEXT="am Ende der Verarbeitungs-Loop"/>
<node CREATED="1697385655730" ID="ID_778822522" MODIFIED="1697385677098" TEXT="kurz darauf w&#xfc;rde er das Lock ein zweites Mal acquiren f&#xfc;r awaitAction()">
<icon BUILTIN="idea"/>
</node>
</node>
</node>
</node>
@ -67257,8 +67312,8 @@
<arrowlink COLOR="#fdfbae" DESTINATION="ID_1349710577" ENDARROW="Default" ENDINCLINATION="-59;-2;" ID="Arrow_ID_1841665742" STARTARROW="None" STARTINCLINATION="-62;3;"/>
</node>
</node>
<node CREATED="1697231321617" ID="ID_1987547541" MODIFIED="1697232150319" TEXT="&#xdc;berarbeitung &#xbb;Emergency-Shutdown&#xab;">
<linktarget COLOR="#4b4593" DESTINATION="ID_1987547541" ENDARROW="Default" ENDINCLINATION="-595;-40;" ID="Arrow_ID_1122128450" SOURCE="ID_756306663" STARTARROW="None" STARTINCLINATION="-613;91;"/>
<node COLOR="#435e98" CREATED="1697231321617" ID="ID_1987547541" MODIFIED="1697375790320" TEXT="&#xdc;berarbeitung &#xbb;Emergency-Shutdown&#xab;">
<linktarget COLOR="#456a93" DESTINATION="ID_1987547541" ENDARROW="Default" ENDINCLINATION="-595;-40;" ID="Arrow_ID_1122128450" SOURCE="ID_756306663" STARTARROW="None" STARTINCLINATION="-831;116;"/>
<node CREATED="1697231405941" ID="ID_1349710577" MODIFIED="1697231547383" TEXT="Vorschlag: es soll ein Deadlock vermieden werden">
<linktarget COLOR="#fdfbae" DESTINATION="ID_1349710577" ENDARROW="Default" ENDINCLINATION="-59;-2;" ID="Arrow_ID_1841665742" SOURCE="ID_1734528491" STARTARROW="None" STARTINCLINATION="-62;3;"/>
<icon BUILTIN="idea"/>
@ -67267,7 +67322,7 @@
<node CREATED="1697231502864" ID="ID_903747246" MODIFIED="1697231589888" TEXT="Fehlerausgang aus einem Subsystem &#x27f9; Heuristik f&#xfc;r korrumpiertes Gesamtsystem"/>
<node CREATED="1697231841691" ID="ID_480459566" MODIFIED="1697231861116" TEXT="daher bei Emergency die Wartezeit begrenzen (und Folgefehler in Kauf nehmen)"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1697231867607" ID="ID_894790570" MODIFIED="1697232116770" TEXT="durch einen Trick im Object-Monitor implementiert">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1697231867607" ID="ID_894790570" MODIFIED="1697375783672" TEXT="war durch einen Trick im Object-Monitor implementiert">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -67276,9 +67331,10 @@
</p>
</body>
</html></richcontent>
<icon BUILTIN="button_cancel"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697232118254" ID="ID_793166861" MODIFIED="1697232131987" TEXT="besser: explizit einen zweiten Wait mit Timemout machen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1697232118254" ID="ID_793166861" MODIFIED="1697375755154" TEXT="besser: explizit einen zweiten Wait mit Timemout machen">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
@ -82134,9 +82190,9 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<linktarget COLOR="#6ebe5a" DESTINATION="ID_125138411" ENDARROW="Default" ENDINCLINATION="43;-18;" ID="Arrow_ID_195305087" SOURCE="ID_215388471" STARTARROW="None" STARTINCLINATION="-113;6;"/>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1695394205547" ID="ID_1719816317" MODIFIED="1696015377362" TEXT="Tests umstellen und modernisieren">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1695394270093" FOLDED="true" ID="ID_585437655" MODIFIED="1696007768225" TEXT="ThreadWrapper_test">
<node COLOR="#338800" CREATED="1695394205547" ID="ID_1719816317" MODIFIED="1697393757628" TEXT="Tests umstellen und modernisieren">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1695394270093" FOLDED="true" ID="ID_585437655" MODIFIED="1697389667338" TEXT="ThreadWrapper_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1695911786871" ID="ID_1371513124" MODIFIED="1695911794232" TEXT="l&#xe4;uft nach Umstellung">
<icon BUILTIN="button_ok"/>
@ -82150,7 +82206,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<head/>
<body>
<p>
Dieser Test ist zwar <i>pfiffig</i>&#160;geschrieben, aber er testet eigentlich den Sync/Monitor, nicht den Thread-Wrapper. In der aktuellen Form ist er sogar nahe an der Thema-Verfehlung, weil &#252;berhaupt nicht getestet wird,&#160; <i>da&#223; mehrere Threads gestartet wurden und gelaufen sind</i>
Dieser Test ist zwar <i>pfiffig</i>&#160;geschrieben, aber er testet eigentlich den Sync/Monitor, nicht den Thread-Wrapper. In der aktuellen Form ist er sogar nahe an der Thema-Verfehlung, weil &#252;berhaupt nicht getestet wird, <i>da&#223; mehrere Threads gestartet wurden und gelaufen sind</i>
</p>
</body>
</html></richcontent>
@ -82624,24 +82680,33 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1695511970250" ID="ID_1548667731" MODIFIED="1695512067599" TEXT="SyncLocking_test ">
<node COLOR="#338800" CREATED="1695511970250" ID="ID_1548667731" MODIFIED="1697393752352" TEXT="SyncLocking_test ">
<linktarget COLOR="#7788a3" DESTINATION="ID_1548667731" ENDARROW="Default" ENDINCLINATION="-97;-50;" ID="Arrow_ID_1461533786" SOURCE="ID_1181374984" STARTARROW="None" STARTINCLINATION="-396;62;"/>
<icon BUILTIN="hourglass"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1695911786871" ID="ID_1433073255" MODIFIED="1695911950387" TEXT="l&#xe4;uft nach Umstellung Thread-Wrapper">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1695511999172" ID="ID_1059124970" MODIFIED="1695512003054" TEXT="SyncClasslock_test">
<icon BUILTIN="hourglass"/>
<node COLOR="#338800" CREATED="1695911786871" ID="ID_915768766" MODIFIED="1695911950387" TEXT="l&#xe4;uft nach Umstellung Thread-Wrapper">
<node COLOR="#338800" CREATED="1697393721571" ID="ID_244182919" MODIFIED="1697393730290" TEXT="l&#xe4;uft nach Umstellung Monitor">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1695512017890" ID="ID_953669300" MODIFIED="1695512023779" TEXT="SyncWaiting_test">
<icon BUILTIN="hourglass"/>
<node COLOR="#338800" CREATED="1695511999172" ID="ID_1059124970" MODIFIED="1697393752352" TEXT="SyncClasslock_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1695911786871" ID="ID_915768766" MODIFIED="1695911950387" TEXT="l&#xe4;uft nach Umstellung Thread-Wrapper">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1697393721571" ID="ID_85406846" MODIFIED="1697393730290" TEXT="l&#xe4;uft nach Umstellung Monitor">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1695512017890" ID="ID_953669300" MODIFIED="1697393752352" TEXT="SyncWaiting_test">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1695911786871" ID="ID_622595151" MODIFIED="1695911950387" TEXT="l&#xe4;uft nach Umstellung Thread-Wrapper">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1697393721571" ID="ID_1065600217" MODIFIED="1697393730290" TEXT="l&#xe4;uft nach Umstellung Monitor">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#338800" CREATED="1695679685747" FOLDED="true" ID="ID_1841477437" MODIFIED="1696368998612" TEXT="DiagnosticContext_test">
<icon BUILTIN="button_ok"/>
@ -83047,10 +83112,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1695394237210" ID="ID_11553358" MODIFIED="1697133471895" TEXT="Applikation umstellen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1695394237210" ID="ID_11553358" MODIFIED="1697393712020" TEXT="Applikation umstellen">
<icon BUILTIN="pencil"/>
<icon BUILTIN="hourglass"/>
<node CREATED="1696029414385" ID="ID_140265798" MODIFIED="1696029417676" TEXT="weitere Tests...">
<node COLOR="#338800" CREATED="1696029465122" ID="ID_1515483274" MODIFIED="1696357491529" TEXT="SubsystemRunner_test">
<icon BUILTIN="button_ok"/>
@ -83644,32 +83707,93 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1693789376921" ID="ID_158507519" MODIFIED="1693789398154" TEXT="ein Monitor geh&#xf6;rt typischerweise in ein Framework"/>
<node CREATED="1693789399454" ID="ID_1417502572" MODIFIED="1693789408745" TEXT="und hier haben wir ein Applicatino-Framework"/>
<node CREATED="1693789410469" ID="ID_1281994248" MODIFIED="1693789423198" TEXT="in diesem Rahmen hat er sich hervorragend bew&#xe4;hrt"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695337735932" HGAP="-30" ID="ID_293636243" MODIFIED="1695337749093" TEXT="Umarbeiten der Implementierung" VSHIFT="40">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1695337750146" ID="ID_99990028" MODIFIED="1695337765337" TEXT="brauchen wir das timedWait-Feature wirklich?">
<node COLOR="#338800" CREATED="1695337735932" HGAP="-30" ID="ID_293636243" MODIFIED="1697393697425" TEXT="Umarbeiten der Implementierung" VSHIFT="40">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1695337750146" ID="ID_99990028" MODIFIED="1697386514303" TEXT="brauchen wir das timedWait-Feature wirklich?">
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="help"/>
<node CREATED="1695337787989" ID="ID_154693007" MODIFIED="1695337808761" TEXT="ich errinnere mich, das nebenbei mit eingebaut zu haben..."/>
<node CREATED="1695337809498" ID="ID_789251448" MODIFIED="1695337825212" TEXT="inzwischen gibt es da diverse bessere M&#xf6;glichkeiten (mit Futures)"/>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1697386278761" ID="ID_1772404839" MODIFIED="1697386519960" TEXT="ja &#x2014; sinnvoll als eigenst&#xe4;ndiges Feature">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Es handelt sich um ein eigenst&#228;ndiges Feature, n&#228;mlich da&#223; ein wait abgebrochen wird
</p>
<ul>
<li>
wir haben daf&#252;r wenige eche use-Cases in der Codebasis (Emergency-Shutdown und Builder-Timeout im Steam-Dispatcher)
</li>
<li>
f&#252;r feste Verz&#246;gerungen gibt es inzwischen std::this_thread::sleep_for
</li>
<li>
Angleichen an das C++ API &#10233; eigenst&#228;ndige Funktion wait_for()
</li>
<li>
R&#252;ckbau der dynamischen &#196;nderbarkeit per setTimeout()
</li>
</ul>
</body>
</html></richcontent>
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695395131329" ID="ID_1209350338" MODIFIED="1696538317493" TEXT="Umstellen der bestehenden Wrapper auf C++14">
<arrowlink COLOR="#e81e74" DESTINATION="ID_963020368" ENDARROW="Default" ENDINCLINATION="-1386;137;" ID="Arrow_ID_750207085" STARTARROW="None" STARTINCLINATION="-379;-555;"/>
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695395162340" ID="ID_188901559" MODIFIED="1695395168717" TEXT="Pr&#xfc;fen auf m&#xf6;gliche Vereinfachungen">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1695395131329" ID="ID_1209350338" MODIFIED="1697386269378" TEXT="Umstellen der bestehenden Wrapper auf C++14">
<arrowlink COLOR="#1e9fe8" DESTINATION="ID_963020368" ENDARROW="Default" ENDINCLINATION="-1386;137;" ID="Arrow_ID_750207085" STARTARROW="None" STARTINCLINATION="-379;-555;"/>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696120192842" ID="ID_276811059" MODIFIED="1696120264827" TEXT="Bug im wait-&#xbb;convenience-shorcut&#xab;">
<node COLOR="#338800" CREATED="1695395162340" ID="ID_188901559" MODIFIED="1697386602627" TEXT="Pr&#xfc;fen auf m&#xf6;gliche Vereinfachungen">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1697386548706" ID="ID_1978159990" MODIFIED="1697386566541" TEXT="Implementierung des Monitors &#x201e;geschrumpft&#x201c;">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1697386567376" ID="ID_1605999602" MODIFIED="1697386600567" TEXT="nur noch &#x3bb;">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node COLOR="#435e98" CREATED="1696120192842" ID="ID_276811059" MODIFIED="1697386048254" TEXT="Bug im wait-&#xbb;convenience-shorcut&#xab;">
<linktarget COLOR="#555dcb" DESTINATION="ID_276811059" ENDARROW="Default" ENDINCLINATION="-1328;-99;" ID="Arrow_ID_707193075" SOURCE="ID_59576653" STARTARROW="None" STARTINCLINATION="-1717;72;"/>
<linktarget COLOR="#682b39" DESTINATION="ID_276811059" ENDARROW="Default" ENDINCLINATION="617;-40;" ID="Arrow_ID_599709584" SOURCE="ID_323663607" STARTARROW="None" STARTINCLINATION="-274;12;"/>
<linktarget COLOR="#cb5590" DESTINATION="ID_276811059" ENDARROW="Default" ENDINCLINATION="-1328;-99;" ID="Arrow_ID_707193075" SOURCE="ID_59576653" STARTARROW="None" STARTINCLINATION="-1717;72;"/>
<icon BUILTIN="broken-line"/>
<node CREATED="1696120269872" ID="ID_538013070" MODIFIED="1696120281507" TEXT="denkbar w&#xe4;re stattdessen eine statische Methode"/>
<node CREATED="1696120282704" ID="ID_1767472760" MODIFIED="1696120305079" TEXT="(oder man verzichtet komplett auf den &#x201e;shortcut&#x201c;)"/>
<node COLOR="#5b280f" CREATED="1696120269872" ID="ID_538013070" MODIFIED="1697386018922" TEXT="denkbar w&#xe4;re stattdessen eine statische Methode">
<icon BUILTIN="button_cancel"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695395186529" ID="ID_110802115" MODIFIED="1695395202288" TEXT="Tests &#xfc;berpr&#xfc;fen und modernisieren">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695395205001" ID="ID_881035953" MODIFIED="1695395208312" TEXT="SyncLocking_test">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1696120282704" ID="ID_1767472760" MODIFIED="1696120305079" TEXT="(oder man verzichtet komplett auf den &#x201e;shortcut&#x201c;)"/>
<node COLOR="#435e98" CREATED="1697386022454" ID="ID_409190764" MODIFIED="1697386045377" TEXT="beste L&#xf6;sung: &#x201e;einfach&#x201c; mal den Bug fixen">
<icon BUILTIN="idea"/>
<node CREATED="1697386085568" ID="ID_584101376" MODIFIED="1697386095475" TEXT="in dem Fall hilft ein explizites try-catch"/>
<node CREATED="1697386096254" ID="ID_953200093" MODIFIED="1697386245340" TEXT="problematisch ist ja nur das wait()">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...weil es im Konstruktor steht, w&#252;rde ein Fehler hier den Konstruktor als <i>gescheitert </i>klassifizieren; dadurch w&#252;rden zwar die Teil-Objekte abgebaut, aber der Objekt-Destruktor nicht aufgerufen. Daher
</p>
<ul>
<li>
das lock() steht ungesch&#252;tzt &#10233; wenn es scheitert mu&#223; auch kein unlock() folgen
</li>
<li>
dagegen das wait() wird gesch&#252;tzt &#10233; bei Exception explizit unlock() und re-throw <font color="#239362">&#10004;</font>
</li>
</ul>
</body>
</html>
</richcontent>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1695395186529" ID="ID_110802115" MODIFIED="1697393693278" TEXT="Tests &#xfc;berpr&#xfc;fen und modernisieren">
<icon BUILTIN="button_ok"/>
<node COLOR="#338800" CREATED="1695395205001" ID="ID_881035953" MODIFIED="1697393541417" TEXT="SyncLocking_test">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1695395218517" ID="ID_1241448952" MODIFIED="1695395351970" TEXT="Kritik: ist zwar fordernd, aber nicht klar">
<richcontent TYPE="NOTE"><html>
<head/>
@ -83680,18 +83804,34 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695395397765" ID="ID_1532807851" MODIFIED="1695395652825" TEXT="Idee: stattdessen den Checker aus ThreadWrapper_test verwenden">
<node COLOR="#435e98" CREATED="1695395397765" ID="ID_1532807851" MODIFIED="1697393488857" TEXT="Idee: stattdessen den Checker aus ThreadWrapper_test verwenden">
<linktarget COLOR="#fedec1" DESTINATION="ID_1532807851" ENDARROW="Default" ENDINCLINATION="416;-16;" ID="Arrow_ID_1646166026" SOURCE="ID_1407826381" STARTARROW="None" STARTINCLINATION="479;36;"/>
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695395436073" ID="ID_735920726" MODIFIED="1695395466899" TEXT="w&#xfc;nschenswert: mit / ohne - Test">
<node COLOR="#435e98" CREATED="1695395436073" ID="ID_735920726" MODIFIED="1697393504852" TEXT="mit / ohne - Test">
<icon BUILTIN="yes"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695395469746" ID="ID_1750044155" MODIFIED="1695395500761" TEXT="den &#xbb;ohne&#xab;-Test so auslegen, da&#xdf; er (fast) immer scheitert">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1695395469746" ID="ID_1750044155" MODIFIED="1697393501674" TEXT="den &#xbb;ohne&#xab;-Test so auslegen, da&#xdf; er (fast) immer scheitert">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695395590676" ID="ID_1887210552" MODIFIED="1695395616570" TEXT="Wirksamkeit ist direkt im Test dokumentiert">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1697393507661" ID="ID_1302265759" MODIFIED="1697393537113" TEXT="Hierzu eine Leerlauf-Policy f&#xfc;r den Monitor bereitstellen">
<icon BUILTIN="button_ok"/>
</node>
<node COLOR="#338800" CREATED="1695395590676" ID="ID_1887210552" MODIFIED="1697393502730" TEXT="Wirksamkeit ist direkt im Test dokumentiert">
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1697393547402" ID="ID_1472144340" MODIFIED="1697393583327" TEXT="SyncWaiting_test">
<icon BUILTIN="button_ok"/>
<node CREATED="1697393567047" ID="ID_692697218" MODIFIED="1697393569675" TEXT="vereinfacht"/>
<node CREATED="1697393570119" ID="ID_1268803288" MODIFIED="1697393582214" TEXT="es gibt jetzt keine verschiedenen Binding-Varianten mehr"/>
</node>
<node COLOR="#338800" CREATED="1697393612553" ID="ID_1734318945" MODIFIED="1697393689392" TEXT="SyncTimedwait_test">
<icon BUILTIN="button_ok"/>
<node CREATED="1697393676649" ID="ID_537743356" MODIFIED="1697393684098" TEXT="keinerlei concurrency"/>
<node CREATED="1697393626992" ID="ID_779548550" MODIFIED="1697393636202" TEXT="pr&#xfc;ft lediglich da&#xdf; ein Timeout passiert"/>
<node CREATED="1697393644213" ID="ID_335589798" MODIFIED="1697393687086" TEXT="ist OK, da es sich ja nun um ein Stdlib-Feature handelt">
<icon BUILTIN="yes"/>
</node>
</node>
</node>