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:
parent
73737f2aee
commit
685be1b039
29 changed files with 544 additions and 477 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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. "
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ namespace asset {
|
|||
//////////////////////////////////////////////////////////TICKET #840 check validity of Ident Category
|
||||
ID<KIND> asset_id (getID (idi));
|
||||
|
||||
DB::Lock guard(®istry);
|
||||
DB::Lock guard{®istry};
|
||||
//////////////////////////////////////////////////////////TICKET #840 handle duplicate Registrations
|
||||
lib::P<KIND> smart_ptr (obj, &destroy);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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())};
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ namespace vault {
|
|||
bool
|
||||
checkRunningState () noexcept override
|
||||
{
|
||||
//Lock guard (*this);
|
||||
//Lock guard{*this};
|
||||
TODO ("implement detecting running state");
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ namespace vault {
|
|||
bool
|
||||
checkRunningState () noexcept override
|
||||
{
|
||||
//Lock guard (*this);
|
||||
//Lock guard{*this};
|
||||
TODO ("implement detecting running state");
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ namespace vault {
|
|||
bool
|
||||
checkRunningState () noexcept override
|
||||
{
|
||||
//Lock guard (*this);
|
||||
//Lock guard{*this};
|
||||
TODO ("implement detecting running state");
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 "
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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ächst aufgebaut auf Christian'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ätzlich Ergänzung um eine TryLock-Variante (als optional<Guard>)"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1697156128590" ID="ID_731556592" MODIFIED="1697156131743" TEXT="Abwägung">
|
||||
<node CREATED="1697156137517" ID="ID_817522107" MODIFIED="1697156191121" TEXT="der »transparente Switch« ist rasch und ohne Risiko umsetzbar">
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1697156128590" ID="ID_731556592" MODIFIED="1697385802949" TEXT="Abwägung">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1697156137517" ID="ID_817522107" MODIFIED="1697385837580" TEXT="der »transparente Switch« 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önnte daher ein Zwischenschritt sein"/>
|
||||
</node>
|
||||
<node CREATED="1697156852566" ID="ID_1056176020" MODIFIED="1697156881277" TEXT="die »strukturelle Verbesserung« stellt längerfristig das Minimum an Code-Qualität dar">
|
||||
<node CREATED="1697156852566" ID="ID_1056176020" MODIFIED="1697385897702" TEXT="die »strukturelle Verbesserung« stellt längerfristig das Minimum an Code-Qualitä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ß nur der Monitor verwendet werden soll..."/>
|
||||
<node CREATED="1697156976195" ID="ID_681854744" MODIFIED="1697156985008" TEXT="deshalb kann auch alles Andere zurückgebaut werden"/>
|
||||
<node CREATED="1697157070044" ID="ID_1501146985" MODIFIED="1697157223059" TEXT="die unique_lock-Instanz ist zugleich Verbesserung und zusätzlicher Ballast">
|
||||
|
|
@ -66595,7 +66601,8 @@
|
|||
<node CREATED="1697157236623" ID="ID_1796494876" MODIFIED="1697157269817" TEXT="die Implementierung im Monitor müßte schrittweise aufgebaut/konsolidiert werden"/>
|
||||
<node CREATED="1697157270541" ID="ID_1316555147" MODIFIED="1697157286077" TEXT="dazu sollte vorher für ausreichende Test-Coverage gesorgt sein"/>
|
||||
</node>
|
||||
<node CREATED="1697157349262" ID="ID_871141135" MODIFIED="1697157367972" TEXT="das »Monitor-Refactoring« entspricht meinem eigenen Qualitäts-Anspruch">
|
||||
<node CREATED="1697157349262" ID="ID_871141135" MODIFIED="1697157349262" TEXT="das »Monitor-Refactoring« entspricht meinem eigenen Qualitäts-Anspruch">
|
||||
<icon BUILTIN="full-3"/>
|
||||
<node CREATED="1697157372112" ID="ID_247839273" MODIFIED="1697157389225" TEXT="das bedeutet: lä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ü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ä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ä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ü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 »timeout« 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ä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ö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ö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ä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ä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ä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ücke, nämlich die const& auf einen rvalue — 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ß im Guard behandelt werden">
|
||||
|
|
@ -66789,8 +66798,7 @@
|
|||
man muß nicht speziell auf den Typ des Trä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ä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 überhaupt sinnvoll, Member-Prädikate speziell zu unterstützen?">
|
||||
|
|
@ -66809,8 +66817,7 @@
|
|||
man hätte dann also zwei verschiedene APIs fü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ö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ür bool-Flags?">
|
||||
<node COLOR="#435e98" CREATED="1697327466147" ID="ID_893621038" MODIFIED="1697370007455" TEXT="dann wohl doch besser ganz unten die Spezalbehandlung für bool-Flags?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1697327490408" ID="ID_608568247" MODIFIED="1697327514952" TEXT="zumindest ist die Policy ein besserer Ort für solche technischen Spezialitäten"/>
|
||||
<node CREATED="1697327515500" ID="ID_1897397765" MODIFIED="1697327536325" TEXT="andererseits ist es dann überhaupt nicht mehr offensichtlich, daß hier Magie passiert"/>
|
||||
|
|
@ -66846,25 +66853,39 @@
|
|||
λ-Notation ist inzwischen allgemein bekannt, und hat den Vorteil, daß das Binding nahe am verwendeten Code liegt. Das gilt ganz besonders auch für bool-Flags, und zudem mü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 — denn λ <i>sind bereits </i>der bessere „Support“
|
||||
</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üfen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1697321155723" ID="ID_1441525836" MODIFIED="1697385542831" TEXT="dann alle Verwendungen auf Modernisierungs-Potential prüfen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1697326991042" ID="ID_163598257" MODIFIED="1697327008100" TEXT="alle Member-Prädikate durch λ ersetzen"/>
|
||||
<node CREATED="1697369952877" ID="ID_599746501" MODIFIED="1697369991005" TEXT="einige notify_* können ohne Lock operieren"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697321173920" ID="ID_599504048" MODIFIED="1697321323733" TEXT="Tickets dokumentieren und schließ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 ¾ fertig vor mir her ... und es ist klar daß ich den letzten Schritt (TYPES<TY....>) noch länger vor mir her schiebe, wiewohl das eigentliche Problem effetiv bereits seit 2017 gelö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 »convenience-shortcut« — 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ü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ü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 ändern — sonst hab ich in jeder dieser delegierenden Funktionen das getMonitor(this), und es ist auch inhaltlich nicht besonders präzise, schließ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ö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äre sogar einigermaßen sicher">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
|
||||
</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
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...und zwar wegen der Typedef "Monitor", die nur im Scope von Sync<CONF>
|
||||
definiert ist — das geht gut, SOLANGE niemand das Layout der Klasse Sync
|
||||
ändert, niemand „aus Versehen“ eine VTable einführt, und solange niemand
|
||||
den Typ Monitor abgreift, woanders instantiiert und dann diese Referenz
|
||||
&#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>
|
||||
über eine von Lock abgeleitete Klasse in die Referenz einspielt. <b><font color="#ea1b82">TJA</font></b> 
|
||||
☹ diesen „Jemand“ gibt es bereits: SyncClasslock <font color="#ad0000">��</font>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="closed"/>
|
||||
</node>
|
||||
<node CREATED="1697324181717" ID="ID_1476992683" MODIFIED="1697324227340" TEXT="Fazit: anständige Leute und so — und außerdem wäre es gefährlich">
|
||||
|
|
@ -66982,10 +67003,22 @@
|
|||
und zwar, weil eine solche anonyme Instanz den umschließenden Scope nicht schü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ß: die Möglichkei bleibt bestehen, wird aber nicht verwendet">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...vielmehr wird das Problem tatsächlich gefixt, durch einen try-catch-Block; die spezielle Konstruktor-Variante bleibt damit erhalten, aber wir bieten generell keinen Support mehr für Member-Funktionen, da dies nur für den Konstruktor möglich wäre, aber nich für die frei stehende wait()-Variante. Ohnehin werden nun Lambdas bevorzugt, weil sie meist am Ort der Verwendung definiert werden und damit besser selbsterklä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üfen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1697319081650" ID="ID_1686143008" MODIFIED="1697385547988" TEXT="alle Verwendungen explizit durchprü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ämlich nicht notwendig, das Lock zu erlangen; aber unser bisheriges API hat dazu gezwungen. Nicht schlimm, aber auch nicht schö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 "this" ist hier eine unglü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ß dazu getMonitor() <b><font color="#58312c">public</font></b> 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ürde er das Lock ein zweites Mal acquiren fü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="Überarbeitung »Emergency-Shutdown«">
|
||||
<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="Überarbeitung »Emergency-Shutdown«">
|
||||
<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 ⟹ Heuristik fü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:   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äuft nach Umstellung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
|
|
@ -82150,7 +82206,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Dieser Test ist zwar <i>pfiffig</i> 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 überhaupt nicht getestet wird,  <i>daß mehrere Threads gestartet wurden und gelaufen sind</i>
|
||||
Dieser Test ist zwar <i>pfiffig</i> 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 überhaupt nicht getestet wird, <i>daß mehrere Threads gestartet wurden und gelaufen sind</i>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
|
|
@ -82624,24 +82680,33 @@ Date:   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ä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äuft nach Umstellung Thread-Wrapper">
|
||||
<node COLOR="#338800" CREATED="1697393721571" ID="ID_244182919" MODIFIED="1697393730290" TEXT="lä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äuft nach Umstellung Thread-Wrapper">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1697393721571" ID="ID_85406846" MODIFIED="1697393730290" TEXT="lä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äuft nach Umstellung Thread-Wrapper">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1697393721571" ID="ID_1065600217" MODIFIED="1697393730290" TEXT="lä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:   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:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node CREATED="1693789376921" ID="ID_158507519" MODIFIED="1693789398154" TEXT="ein Monitor gehö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ä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öglichkeiten (mit Futures)"/>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1697386278761" ID="ID_1772404839" MODIFIED="1697386519960" TEXT="ja — sinnvoll als eigenständiges Feature">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Es handelt sich um ein eigenständiges Feature, nämlich daß ein wait abgebrochen wird
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
wir haben dafür wenige eche use-Cases in der Codebasis (Emergency-Shutdown und Builder-Timeout im Steam-Dispatcher)
|
||||
</li>
|
||||
<li>
|
||||
für feste Verzögerungen gibt es inzwischen std::this_thread::sleep_for
|
||||
</li>
|
||||
<li>
|
||||
Angleichen an das C++ API ⟹ eigenständige Funktion wait_for()
|
||||
</li>
|
||||
<li>
|
||||
Rückbau der dynamischen Ä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üfen auf mö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-»convenience-shorcut«">
|
||||
<node COLOR="#338800" CREATED="1695395162340" ID="ID_188901559" MODIFIED="1697386602627" TEXT="Prüfen auf mögliche Vereinfachungen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1697386548706" ID="ID_1978159990" MODIFIED="1697386566541" TEXT="Implementierung des Monitors „geschrumpft“">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1697386567376" ID="ID_1605999602" MODIFIED="1697386600567" TEXT="nur noch λ">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1696120192842" ID="ID_276811059" MODIFIED="1697386048254" TEXT="Bug im wait-»convenience-shorcut«">
|
||||
<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äre stattdessen eine statische Methode"/>
|
||||
<node CREATED="1696120282704" ID="ID_1767472760" MODIFIED="1696120305079" TEXT="(oder man verzichtet komplett auf den „shortcut“)"/>
|
||||
<node COLOR="#5b280f" CREATED="1696120269872" ID="ID_538013070" MODIFIED="1697386018922" TEXT="denkbar wä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 überprü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 „shortcut“)"/>
|
||||
<node COLOR="#435e98" CREATED="1697386022454" ID="ID_409190764" MODIFIED="1697386045377" TEXT="beste Lösung: „einfach“ 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ürde ein Fehler hier den Konstruktor als <i>gescheitert </i>klassifizieren; dadurch würden zwar die Teil-Objekte abgebaut, aber der Objekt-Destruktor nicht aufgerufen. Daher
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
das lock() steht ungeschützt ⟹ wenn es scheitert muß auch kein unlock() folgen
|
||||
</li>
|
||||
<li>
|
||||
dagegen das wait() wird geschützt ⟹ bei Exception explizit unlock() und re-throw <font color="#239362">✔</font>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1695395186529" ID="ID_110802115" MODIFIED="1697393693278" TEXT="Tests überprü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:   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ü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 »ohne«-Test so auslegen, daß er (fast) immer scheitert">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1695395469746" ID="ID_1750044155" MODIFIED="1697393501674" TEXT="den »ohne«-Test so auslegen, daß 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ü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üft lediglich daß 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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue