Library/Application: switch Locking from POSIX to C++14

While not directly related to the thread handling framework,
it seems indicated to clean-up this part of the application alongside.

For »everyday« locking concerns, an Object Monitor abstraction was built
several years ago and together with the thread-wrapper, both at that time
based on direct usage of POSIX. This changeset does a mere literal
replacement of the POSIX calls with the corresponding C++ wrappers
on the lowest level. The resulting code is needlessly indirect, yet
at API-level this change is totally a drop-in replacment.
This commit is contained in:
Fischlurch 2023-10-13 23:46:38 +02:00
parent 1c4f605e8f
commit c37871ca78
7 changed files with 510 additions and 293 deletions

View file

@ -166,6 +166,9 @@ namespace lumiera {
wait ()
{
Lock wait_blocking(this, &SubsystemRunner::allDead);
////////////////////////////////////////////////////////////OOO Emergency-Exit richtig implementieren
if (isEmergencyExit())
usleep(2*1000*1000);
return isEmergencyExit();
}
@ -223,9 +226,11 @@ namespace lumiera {
{
if (isEmergencyExit())
{
Lock sync(this);
if (!sync.isTimedWait())
sync.setTimeout(EMERGENCYTIMEOUT);
// Lock sync(this);
// if (!sync.isTimedWait())
// sync.setTimeout(EMERGENCYTIMEOUT);
////////////////////////////////////////////////////////////OOO Emergency-Exit richtig implementieren
return true;
}
return isnil (running_); // end wait if no running subsystem left

View file

@ -1,72 +0,0 @@
/*
Sync - generic helper for object based locking and synchronisation
Copyright (C) Lumiera.org
2011, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
/** @file sync.cpp
** This compilation unit holds the static attribute struct
** for initialising pthread's recursive mutex.
**
*/
#include "lib/sync.hpp"
namespace lib {
namespace sync {
namespace { // private pthread attributes
pthread_mutexattr_t attribute_;
void
initAttribute()
{
pthread_mutexattr_init (&attribute_);
pthread_mutexattr_settype (&attribute_, PTHREAD_MUTEX_RECURSIVE);
}
inline pthread_mutexattr_t*
recursive_flag()
{
static pthread_once_t _is_init_sync_mutex_attribute_(PTHREAD_ONCE_INIT);
pthread_once (&_is_init_sync_mutex_attribute_, initAttribute);
return &attribute_;
}
}
/**
* @internal creating a recursive mutex.
* Defined here in a separate compilation unit,
* so it can refer to a single mutex attribute flag.
*/
Wrapped_RecursiveMutex::Wrapped_RecursiveMutex()
{
pthread_mutex_init (&mutex_, recursive_flag());
}
}}// lib::sync

View file

@ -14,7 +14,7 @@
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@ -46,16 +46,17 @@
** - You can't use the Lock#wait and Lock#notify functions unless you pick
** a parametrisation including a condition variable.
** - 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
** 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.
** 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
** @see mutex.h
** @see sync-locking-test.cpp
** @see sync-waiting-test.cpp
@ -70,14 +71,10 @@
#include "lib/error.hpp"
#include "lib/nocopy.hpp"
#include "lib/util.hpp"
extern "C" {
#include "lib/lockerror.h"
}
#include <pthread.h>
#include <cerrno>
#include <ctime>
#include <mutex>
#include <condition_variable>
#include <chrono>
@ -92,62 +89,47 @@ namespace lib {
/* ========== adaptation layer for accessing backend/system level code ============== */
struct Wrapped_ExclusiveMutex
: util::NonCopyable
{
pthread_mutex_t mutex_;
std::mutex mutex_;
protected:
Wrapped_ExclusiveMutex()
{
pthread_mutex_init (&mutex_, NULL);
}
~Wrapped_ExclusiveMutex()
{
if (pthread_mutex_destroy (&mutex_))
ERROR (sync, "Failure destroying mutex.");
} // shouldn't happen in a correct program
Wrapped_ExclusiveMutex() = default;
void
lock()
{
if (pthread_mutex_lock (&mutex_))
throw lumiera::error::Fatal ("Mutex acquire failed");
} // shouldn't happen in a correct program
mutex_.lock();
}
void
unlock()
{
if (pthread_mutex_unlock (&mutex_))
ERROR (sync, "Failure unlocking mutex.");
} // shouldn't happen in a correct program
mutex_.unlock();
}
};
struct Wrapped_RecursiveMutex
: util::NonCopyable
{
pthread_mutex_t mutex_;
std::recursive_mutex mutex_;
protected:
Wrapped_RecursiveMutex();
~Wrapped_RecursiveMutex()
{
if (pthread_mutex_destroy (&mutex_))
ERROR (sync, "Failure destroying (rec)mutex.");
} // shouldn't happen in a correct program
Wrapped_RecursiveMutex() = default;
void
lock()
{
if (pthread_mutex_lock (&mutex_))
throw lumiera::error::Fatal ("(rec)Mutex acquire failed");
} // shouldn't happen in a correct program
mutex_.lock();
}
void
unlock()
{
if (pthread_mutex_unlock (&mutex_))
ERROR (sync, "Failure unlocking (rec)mutex.");
} // shouldn't happen in a correct program
mutex_.unlock();
}
};
@ -155,44 +137,27 @@ namespace lib {
struct Wrapped_Condition
: MTX
{
pthread_cond_t cond_;
std::condition_variable_any cond_;
protected:
Wrapped_Condition()
{
pthread_cond_init (&cond_, NULL);
}
~Wrapped_Condition()
{
if (pthread_cond_destroy (&cond_))
ERROR (sync, "Failure destroying condition variable.");
} // shouldn't happen in a correct program
Wrapped_Condition() = default;
bool
void
wait()
{
int err;
do { err = pthread_cond_wait (&this->cond_, &this->mutex_);
} while(err == EINTR);
if (err) lumiera_lockerror_set (err, &NOBUG_FLAG(sync), NOBUG_CONTEXT_NOFUNC);
return not err;
cond_.wait (this->mutex_);
}
template<class REPR, class PERI>
bool
timedwait (const struct timespec* timeout)
timedwait (std::chrono::duration<REPR, PERI> const& timeout)
{
int err;
do { err = pthread_cond_timedwait (&this->cond_, &this->mutex_, timeout);
} while(err == EINTR);
if (err) lumiera_lockerror_set (err, &NOBUG_FLAG(sync), NOBUG_CONTEXT_NOFUNC);
return not err;
auto ret = cond_.wait_for (this->mutex_, timeout);
return (std::cv_status::no_timeout == ret);
}
void signal() { pthread_cond_signal (&cond_); }
void broadcast() { pthread_cond_broadcast (&cond_); }
void signal() { cond_.notify_one(); }
void broadcast() { cond_.notify_all(); }
};
@ -208,10 +173,7 @@ namespace lib {
: protected MTX
{
protected:
~Mutex () { }
Mutex () { }
Mutex (const Mutex&); ///< noncopyable...
const Mutex& operator= (const Mutex&);
Mutex () = default;
public:
void
@ -229,43 +191,6 @@ namespace lib {
/**
* helper for specifying an optional timeout for an timed wait.
* Wrapping a timespec-struct, it allows for easy initialisation
* by a given relative offset.
* @todo integrate with std::chrono //////////////////////////TICKET #1055
*/
struct Timeout
: timespec
{
Timeout() { reset(); }
void reset() { tv_sec=tv_nsec=0; }
/** initialise to NOW() + offset (in milliseconds) */
Timeout&
setOffset (ulong offs)
{
if (offs)
{
clock_gettime(CLOCK_REALTIME, this); //////////////////////////TICKET #886
tv_sec += offs / 1000;
tv_nsec += 1000000 * (offs % 1000);
if (tv_nsec >= 1000000000)
{
tv_sec += tv_nsec / 1000000000;
tv_nsec %= 1000000000;
} }
else
reset();
return *this;
}
explicit operator bool() { return 0 != tv_sec; } // allows if (timeout_)....
};
template<class MTX>
class Condition
: public Mutex<Wrapped_Condition<MTX>>
@ -283,20 +208,19 @@ namespace lib {
}
/** @return `false` in case of timeout */
template<class BF>
bool
wait (BF& predicate, Timeout& waitEndTime)
wait (BF& predicate, uint timeout_ms =0)
{
bool ok = true;
while (ok and !predicate())
if (waitEndTime)
ok = Cond::timedwait (&waitEndTime);
while (not predicate())
if (timeout_ms != 0)
{
if (not Cond::timedwait (std::chrono::milliseconds (timeout_ms)))
return false;
}
else
ok = Cond::wait ();
if (not ok and lumiera_error_expect(LUMIERA_ERROR_LOCK_TIMEOUT)) return false;
lumiera::throwOnError(); // any other error throws
Cond::wait ();
return true;
}
};
@ -340,15 +264,13 @@ namespace lib {
class Monitor
: IMPL
{
Timeout timeout_;
public:
Monitor() {}
~Monitor() {}
/** allow copy, without interfering with the identity of IMPL */
Monitor (Monitor const& ref) : IMPL(), timeout_(ref.timeout_) { }
const Monitor& operator= (Monitor const& ref) { timeout_ = ref.timeout_; return *this; }
Monitor (Monitor const& ref) : IMPL() { }
const Monitor& operator= (Monitor const& ref) { /*prevent assignment to base*/ return *this; }
void acquireLock() { IMPL::acquire(); }
@ -357,22 +279,19 @@ namespace lib {
void signal(bool a){ IMPL::signal(a); }
bool
wait (Flag flag, ulong timedwait=0)
wait (Flag flag, ulong timedwait_ms=0)
{
BoolFlagPredicate checkFlag(flag);
return IMPL::wait(checkFlag, timeout_.setOffset(timedwait));
return IMPL::wait(checkFlag, timedwait_ms);
}
template<class X>
bool
wait (X& instance, bool (X::*method)(void), ulong timedwait=0) ///////////////////////TICKET #1051 : add support for lambdas
wait (X& instance, bool (X::*method)(void), ulong timedwait_ms=0) /////////////////////TICKET #1051 : add support for lambdas
{
BoolMethodPredicate<X> invokeMethod(instance, method); ///////////////////////TICKET #1057 : const correctness, allow use of const member functions
return IMPL::wait(invokeMethod, timeout_.setOffset(timedwait));
return IMPL::wait(invokeMethod, timedwait_ms);
}
void setTimeout(ulong relative) {timeout_.setOffset(relative);}
bool isTimedWait() {return bool{timeout_};}
};
typedef Mutex<Wrapped_ExclusiveMutex> NonrecursiveLock_NoWait;
@ -455,8 +374,6 @@ namespace lib {
void notify() { mon_.signal(false);}
void notifyAll() { mon_.signal(true); }
void setTimeout(ulong time) { mon_.setTimeout(time); }
bool isTimedWait() { return mon_.isTimedWait(); }
template<typename C>
bool
@ -467,7 +384,7 @@ namespace lib {
template<typename X>
bool
wait (X& instance, bool (X::*predicate)(void), ulong timeout=0) //////////////////////TICKET #1051 : enable use of lambdas
wait (X& instance, bool (X::*predicate)(void), ulong timeout=0) //////////////////////TICKET #1051 : enable use of lambdas
{
return mon_.wait(instance,predicate,timeout);
}
@ -480,8 +397,8 @@ namespace lib {
*/
template<class X>
Lock(X* it, bool (X::*method)(void))
: mon_(getMonitor(it))
{
: mon_(getMonitor(it))
{
mon_.acquireLock();
mon_.wait(*it,method);
}

View file

@ -82,7 +82,7 @@ namespace test{
inline double
benchmarkTime (FUN const& invokeTestLoop, const size_t repeatCnt = DEFAULT_RUNS)
{
using std::chrono::system_clock;
using std::chrono::system_clock;; /////////////////////////////////////////TICKET #886
using Dur = std::chrono::duration<double, CLOCK_SCALE>;
auto start = system_clock::now();

View file

@ -29,6 +29,7 @@
#include "lib/test/test-helper.hpp"
#include "lib/diagnostic-context.hpp"
#include "lib/iter-explorer.hpp"
#include "lib/thread.hpp"
#include <vector>
@ -171,10 +172,14 @@ namespace test{
}
};
std::array<TestThread, NUM_THREADS> testcase;
for (uint i=0; i < NUM_THREADS; ++i)
verifyResult (testcase[i].join());
std::array<TestThread, NUM_THREADS> testcases;
auto results = lib::explore(testcases)
.transform([](TestThread& t){ return t.join(); })
.effuse();
for (auto& res : results)
verifyResult (res);
}

View file

@ -27,27 +27,25 @@
#include "lib/test/run.hpp"
#include "lib/error.hpp"
#include "lib/sync.hpp"
#include <iostream>
#include <chrono>
using std::cout;
using test::Test;
using std::chrono::system_clock;
namespace lib {
namespace test{
namespace { // private test classes and data...
namespace { // test parameters...
const uint WAIT_mSec = 200; ///< milliseconds to wait before timeout
const uint WAIT_mSec = 20; ///< milliseconds to wait before timeout
using CLOCK_SCALE = std::milli; // Results are in ms
using Dur = std::chrono::duration<double, CLOCK_SCALE>;
} // (End) test classes and data....
}//(End) parameters
@ -55,25 +53,16 @@ namespace test{
/****************************************************************************//**
* @test timeout feature on condition wait as provided by pthread and accessible
* via the object monitor based locking/waiting mechanism. Without creating
* multiple threads, we engage into a blocking wait, which aborts due to
* setting a timeout. Our waiting facility is written such as to invoke
* the condition prior to entering wait state (and consecutively whenever
* awakened). This test switches into wait-with-timeout mode right from
* within this condition check and thus works even while there is no
* other thread and thus an unconditional wait would stall forever.
*
* @note it is discouraged to use the timed wait feature for "timing";
* when possible you should prefer relying on the Lumiera scheduler
*
* @test timeout feature on condition wait as provided by the underlying implementation
* and accessible via the object monitor based locking/waiting mechanism. Without
* creating multiple threads, we engage into a blocking wait, which aborts due to
* setting a timeout.
* @see SyncWaiting_test
* @see sync::Timeout
* @see sync.hpp
*/
class SyncTimedwait_test
: public Test,
Sync<RecursiveLock_Waitable>
Sync<NonrecursiveLock_Waitable>
{
friend class Lock; // allows inheriting privately from Sync
@ -82,60 +71,19 @@ namespace test{
virtual void
run (Arg)
{
checkTimeoutStruct();
Lock lock(this);
Lock block(this, &SyncTimedwait_test::neverHappens);
auto start = system_clock::now();
bool salvation{false};
bool fulfilled = lock.wait (salvation, WAIT_mSec);
cout << "back from LaLaLand, alive and thriving!\n";
CHECK (block.isTimedWait());
CHECK (not fulfilled); // condition not fulfilled, but timeout
Dur duration = system_clock::now () - start;
CHECK (WAIT_mSec <= duration.count());
CHECK (duration.count() < 2*WAIT_mSec);
}
bool
neverHappens() ///< the "condition test" used for waiting....
{
Lock currentLock(this); // get the Lock recursively
if (!currentLock.isTimedWait()) // right from within the condition check:
currentLock.setTimeout(WAIT_mSec); // switch waiting mode to timed wait and set timeout
return false;
}
void
checkTimeoutStruct()
{
sync::Timeout tout;
CHECK (!tout);
CHECK (0 == tout.tv_sec);
CHECK (0 == tout.tv_nsec);
tout.setOffset (0);
CHECK (!tout);
CHECK (0 == tout.tv_sec);
CHECK (0 == tout.tv_nsec);
timespec ref;
clock_gettime(CLOCK_REALTIME, &ref);
tout.setOffset (1);
CHECK (tout);
CHECK (0 < tout.tv_sec);
CHECK (ref.tv_sec <= tout.tv_sec);
CHECK (ref.tv_nsec <= 1000000 + tout.tv_nsec || ref.tv_nsec > 1000000000-100000);
clock_gettime(CLOCK_REALTIME, &ref);
tout.setOffset (1000);
CHECK (tout);
if (ref.tv_nsec!=0) // should have gotten an overflow to the seconds part
{
CHECK (ref.tv_sec <= 2 + tout.tv_sec );
CHECK ((ref.tv_nsec + 1000000 * 999) % 1000000000
<= tout.tv_nsec);
}
}
};

View file

@ -66343,9 +66343,9 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1696538243989" ID="ID_963020368" MODIFIED="1696538317493" TEXT="Objekt-Monitor (Wrapper)">
<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;"/>
<icon BUILTIN="hourglass"/>
<icon BUILTIN="pencil"/>
<node CREATED="1696538320106" ID="ID_1371656828" MODIFIED="1696538327925" TEXT="Wrapper bestand schon bisher">
<node CREATED="1696538329153" ID="ID_23495962" MODIFIED="1696538341970" TEXT="war zun&#xe4;chst aufgebaut auf Christian&apos;s NoBug-Adapter"/>
<node CREATED="1696538342567" ID="ID_1615743688" MODIFIED="1696538354117" TEXT="dann umgestellt auf direkte Verwendung von POSIX"/>
@ -66360,10 +66360,334 @@
<icon BUILTIN="idea"/>
</node>
</node>
<node CREATED="1696538455872" ID="ID_795722171" MODIFIED="1696538460260" TEXT="C++14-Wrapper"/>
<node CREATED="1696538455872" ID="ID_795722171" MODIFIED="1696538460260" TEXT="C++14-Wrapper">
<node CREATED="1697151693240" ID="ID_254039362" MODIFIED="1697151699355" TEXT="relevant">
<node CREATED="1697151748256" ID="ID_1985516619" MODIFIED="1697151819444" TEXT="mutex">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1985516619" ENDARROW="Default" ENDINCLINATION="133;0;" ID="Arrow_ID_591394395" SOURCE="ID_1259850998" STARTARROW="None" STARTINCLINATION="115;0;"/>
</node>
<node CREATED="1697151750928" ID="ID_1683342529" MODIFIED="1697151811512" TEXT="recursive_mutex">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_1683342529" ENDARROW="Default" ENDINCLINATION="51;0;" ID="Arrow_ID_1845277195" SOURCE="ID_1259850998" STARTARROW="None" STARTINCLINATION="51;0;"/>
</node>
<node CREATED="1697151767230" ID="ID_1435647108" MODIFIED="1697151769601" TEXT="condition_var">
<node CREATED="1697152084523" HGAP="95" ID="ID_605165052" MODIFIED="1697152104685" TEXT="zwingend an unique_lock + ein mutex gebunden" VSHIFT="6"/>
</node>
<node CREATED="1697151774377" ID="ID_1259850998" MODIFIED="1697151819444" TEXT="unique_lock">
<arrowlink DESTINATION="ID_1683342529" ENDARROW="Default" ENDINCLINATION="51;0;" ID="Arrow_ID_1845277195" STARTARROW="None" STARTINCLINATION="51;0;"/>
<arrowlink DESTINATION="ID_1985516619" ENDARROW="Default" ENDINCLINATION="133;0;" ID="Arrow_ID_591394395" STARTARROW="None" STARTINCLINATION="115;0;"/>
<node CREATED="1697152113215" HGAP="93" ID="ID_950739856" MODIFIED="1697152434282" TEXT="ist ein (flexiblerer) lock_guard..." VSHIFT="5">
<arrowlink DESTINATION="ID_944756854" ENDARROW="Default" ENDINCLINATION="171;0;" ID="Arrow_ID_120128551" STARTARROW="None" STARTINCLINATION="-9;17;"/>
<node CREATED="1697152145940" ID="ID_276145575" MODIFIED="1697152151934" TEXT="normalerweise im ctor gelockt"/>
<node CREATED="1697152152402" ID="ID_1887916464" MODIFIED="1697152158165" TEXT="kann aber ungelockt erstellt werden"/>
<node CREATED="1697152161546" ID="ID_802566279" MODIFIED="1697152196264" TEXT="kann trylock machen, auch im ctor"/>
<node CREATED="1697152207265" ID="ID_1526785209" MODIFIED="1697152220429" TEXT="kann explizit unlocked werden, und dann sp&#xe4;ter wieder gelockt"/>
</node>
</node>
<node CREATED="1697151783060" ID="ID_944756854" MODIFIED="1697152438468" TEXT="lock_guard">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_944756854" ENDARROW="Default" ENDINCLINATION="171;0;" ID="Arrow_ID_120128551" SOURCE="ID_950739856" STARTARROW="None" STARTINCLINATION="-9;17;"/>
<linktarget COLOR="#a9b4c1" DESTINATION="ID_944756854" ENDARROW="Default" ENDINCLINATION="300;0;" ID="Arrow_ID_253725530" SOURCE="ID_6034412" STARTARROW="None" STARTINCLINATION="300;0;"/>
</node>
<node CREATED="1697151896093" HGAP="22" ID="ID_1465275644" MODIFIED="1697151914560" TEXT="andere" VSHIFT="17">
<node CREATED="1697151926997" ID="ID_801192171" MODIFIED="1697151931804" TEXT="shared_mutex">
<node CREATED="1697152263803" ID="ID_1586207113" MODIFIED="1697152273528" TEXT="hat zwei lock-Modi: exclusive und shared"/>
<node CREATED="1697152275370" ID="ID_1656757256" MODIFIED="1697152297738" TEXT="shared-lock kann nur erlangt werden, wenn es kein exclusive lock gibt"/>
<node CREATED="1697152298207" ID="ID_1153249756" MODIFIED="1697152311099" TEXT="use-case: shared reading, exclusive writing"/>
</node>
<node CREATED="1697151937271" ID="ID_1732379198" MODIFIED="1697151940029" TEXT="timed_mutex">
<node CREATED="1697152313437" ID="ID_1264555835" MODIFIED="1697152324127" TEXT="bietet zus&#xe4;tzlich timeouts"/>
</node>
<node CREATED="1697152072365" ID="ID_1696650993" MODIFIED="1697152075403" TEXT="scoped_lock">
<node CREATED="1697152328107" ID="ID_6034412" MODIFIED="1697152438468" TEXT="ein spezieller lock-guard">
<arrowlink DESTINATION="ID_944756854" ENDARROW="Default" ENDINCLINATION="300;0;" ID="Arrow_ID_253725530" STARTARROW="None" STARTINCLINATION="300;0;"/>
</node>
<node CREATED="1697152345096" ID="ID_234957929" MODIFIED="1697152357178" TEXT="kann aber mehrere Locks atomar erlangen"/>
<node CREATED="1697152358271" ID="ID_35680042" MODIFIED="1697152371417" TEXT="und dabei eine Deadlock-Vermeidungsstrategie anwenden">
<node CREATED="1697152546245" ID="ID_1179913701" MODIFIED="1697152553352" TEXT="ruft eigentlich den algo std::lock auf"/>
<node CREATED="1697152558001" ID="ID_721786307" MODIFIED="1697152570462" TEXT="dieser pr&#xfc;ft intelligent den locking-Zustand"/>
<node CREATED="1697152611045" ID="ID_16304346" MODIFIED="1697152621727" TEXT="und entsperrt alle Locks im Fehlerfall"/>
</node>
</node>
</node>
</node>
<node CREATED="1697152640957" ID="ID_1468664263" MODIFIED="1697152644272" TEXT="Einsch&#xe4;tzung">
<node CREATED="1697152645136" ID="ID_1133656270" MODIFIED="1697152651011" TEXT="v&#xf6;llig unproblematisch"/>
<node CREATED="1697152651631" ID="ID_683393307" MODIFIED="1697152662130" TEXT="hier wird die POSIX-Semantik 1:1 durchgereicht"/>
<node CREATED="1697152671557" ID="ID_591975919" MODIFIED="1697152945571" TEXT="Twist">
<node CREATED="1697152946704" ID="ID_828959106" MODIFIED="1697152946704" TEXT="condition_var will ein bereits erlangtes unique_lock">
<node CREATED="1697153345130" ID="ID_1006609083" MODIFIED="1697153357503" TEXT="bei POSIX ist das einfach eine Precondition"/>
<node CREATED="1697153358136" ID="ID_833851692" MODIFIED="1697153372234" TEXT="unsere bisherige Impl stellt das auch nur kontextuell sicher"/>
<node CREATED="1697153375126" ID="ID_84530625" MODIFIED="1697153390904" TEXT="dagegen durch das unique_lock wird das materialisiert"/>
<node COLOR="#5b280f" CREATED="1697153721983" ID="ID_1120978458" MODIFIED="1697211295181" TEXT="es gibt aber den &#xbb;adopt lock&#xab;-Mechanismus">
<icon BUILTIN="button_cancel"/>
<node CREATED="1697211296788" ID="ID_516008091" MODIFIED="1697211306007" TEXT="nein: das hilft nicht"/>
<node CREATED="1697211306619" ID="ID_20444784" MODIFIED="1697211430279" TEXT="unique_lock kann selber nicht rekursiv assoziiert werden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Es kann zwar ein rekursives Mutex verwenden, aber jede Ebene von Locking mu&#223; dann als eigenes unique_lock-Token repr&#228;sentiert werden.
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1697211431074" ID="ID_921453654" MODIFIED="1697211474012" TEXT="&#x27f9; unique_lock kann daher nicht gemeinsam mit mehreren Threads arbeiten"/>
</node>
<node CREATED="1697211475596" ID="ID_1432080537" MODIFIED="1697211499297" TEXT="alternativ: die allgemeine condition_var_any verwenden">
<icon BUILTIN="idea"/>
<node CREATED="1697211738347" ID="ID_1470675670" MODIFIED="1697211757821">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
diese setzt nur ein <i>BasicLockable</i>&#160;voraus
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1697211758557" ID="ID_1308356052" MODIFIED="1697211769888">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
Mutex selber ist bereits <i>BasicLockable</i>
</p>
</body>
</html>
</richcontent>
</node>
</node>
</node>
<node CREATED="1697153008914" ID="ID_939982348" MODIFIED="1697153033086" TEXT="keine Error-R&#xfc;ckgabecodes mehr. Stattdessen throw std::system_error"/>
<node COLOR="#435e98" CREATED="1697208294038" ID="ID_724408266" MODIFIED="1697208642249">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
die C++ - Wrapper sind <b>non-copyable</b>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1697208611826" ID="ID_1407647722" MODIFIED="1697226243538" TEXT="was man synchronisiert, hat typischerweise Referenz-Semantik">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697208590782" ID="ID_1383871199" MODIFIED="1697226552108" TEXT="aber: class Monitor erlaubt Brechen dieser Bedingung">
<linktarget COLOR="#c36885" DESTINATION="ID_1383871199" ENDARROW="Default" ENDINCLINATION="-768;38;" ID="Arrow_ID_1367033811" SOURCE="ID_1311077272" STARTARROW="None" STARTINCLINATION="-220;-13;"/>
<icon BUILTIN="broken-line"/>
<node CREATED="1697226328908" ID="ID_1205179392" MODIFIED="1697226343430" TEXT="er hat einen Copy-Konstruktor und Assignment"/>
<node CREATED="1697226345928" ID="ID_244225602" MODIFIED="1697226360003" TEXT="diese erzeugen jeweils einfach eine neue Implementierung"/>
<node CREATED="1697226360536" ID="ID_1800556938" MODIFIED="1697226426877" TEXT="nicht die feine englische Art">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...gegebenfalls kann es dadurch passieren, da&#223; man ein grade gesperrtes Mutex einfach &#8222;fahren l&#228;&#223;t&#8220; &#8212; mit unabsehbaren Folgen
</p>
</body>
</html>
</richcontent>
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
</node>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1697153970230" ID="ID_1218189224" MODIFIED="1697153991860" TEXT="Herangehensweise?">
<icon BUILTIN="help"/>
<node CREATED="1697153994987" ID="ID_678749516" MODIFIED="1697153998214" TEXT="Situation">
<node CREATED="1697153999066" ID="ID_1857771089" MODIFIED="1697154022235" TEXT="ich habe ein relativ koh&#xe4;sives St&#xfc;ck Code mit einem schmalen API nach au&#xdf;en"/>
<node CREATED="1697154049196" ID="ID_1905385027" MODIFIED="1697154074365" TEXT="der Code wurde bereits mehrfach umgeschrieben und &#x201e;aufgebohrt&#x201c; f&#xfc;r Timeouts"/>
<node CREATED="1697154093695" ID="ID_680368704" MODIFIED="1697154108078" TEXT="der Code ist sehr gut gegliedert; es gibt einen low-Level-Layer"/>
<node CREATED="1697154131456" ID="ID_1645036069" MODIFIED="1697154252320" TEXT="der Code orientiert sich an POSIX &#x27f9; er ist Konventions-orientiert">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Genauer gesagt, der Code versucht, die Konventions-basierte Herangehensweise aus POSIX / C in einen Token-orientierten Ansatz f&#252;r C++ zu &#252;bersetzen. Das bedeutet aber, auch das Monitor-API ist noch Konventions-basiert
</p>
</body>
</html></richcontent>
</node>
</node>
<node CREATED="1697154260247" ID="ID_685378325" MODIFIED="1697154263707" TEXT="M&#xf6;glichkeiten">
<node CREATED="1697154266598" ID="ID_1270232575" MODIFIED="1697154286783" TEXT="transparenter Switch">
<node CREATED="1697154290739" ID="ID_760570676" MODIFIED="1697154353526" TEXT="in den low-Level Wrapper wird einfach der POSIX-Code durch C++-Wrapper ersetzt"/>
<node CREATED="1697154355514" ID="ID_165826479" MODIFIED="1697154371436" TEXT="nach M&#xf6;glichkeit sollte bereits das API der low-Level Wrapper unver&#xe4;ndert bleiben"/>
<node CREATED="1697154383255" ID="ID_1951392587" MODIFIED="1697211542815" TEXT="kein unique_lock verwenden, sondern die unspezifische condition_var_any"/>
<node CREATED="1697154499291" ID="ID_1226519053" MODIFIED="1697154527047" TEXT="in ConditionVar wird versucht, die R&#xfc;ckgabe-Werte und den Timeout analog nachzubilden"/>
<node CREATED="1697154535460" ID="ID_353347483" MODIFIED="1697154557475" TEXT="Resultat &#x27f9; der Lock-Guard dar&#xfc;ber verh&#xe4;lt sich 1:1 identisch"/>
<node CREATED="1697154566590" ID="ID_1192462258" MODIFIED="1697154587375" TEXT="anschlie&#xdf;end k&#xf6;nnte man noch &#x3bb;-support einbauen"/>
</node>
<node CREATED="1697154592299" ID="ID_1809860327" MODIFIED="1697154630897" TEXT="strukturelle Verbesserung">
<node CREATED="1697154638261" ID="ID_1493391144" MODIFIED="1697154656991" TEXT="nur die Monitor-Klasse bleibt &#xe4;quivalent erhalten"/>
<node CREATED="1697154664352" ID="ID_453928483" MODIFIED="1697154681027" TEXT="die zwei Ebenen Wrapper darunter werden durch Typedefs auf C++-Wrapper ersetzt"/>
<node CREATED="1697155716573" ID="ID_1758887952" MODIFIED="1697155738480" TEXT="oder genauer: in Policy-Klassen zusammengefa&#xdf;t"/>
<node CREATED="1697155742090" ID="ID_311928425" MODIFIED="1697211635523" TEXT="auch hier kann kein unique_lock verwendet werden"/>
</node>
<node CREATED="1697155790803" ID="ID_1122062252" MODIFIED="1697155795238" TEXT="Monitor-Refactoring">
<node CREATED="1697155797458" ID="ID_1050112760" MODIFIED="1697155862237" TEXT="Monitor l&#xf6;st sich vom Lehrbuch-Schema"/>
<node CREATED="1697155866508" ID="ID_607921464" MODIFIED="1697155887706" TEXT="stattdessen wird der Token-Ansatz bereits im Monitor verankert"/>
<node CREATED="1697155965676" ID="ID_736666954" MODIFIED="1697155999305" TEXT="das hei&#xdf;t: man bekommt vom Monitor einen Guard-mit-Proze&#xdf;-API"/>
<node CREATED="1697156007104" ID="ID_1780881398" MODIFIED="1697156030745" TEXT="der Lock-Guard ist dann nur noch ein Konstruktor-Wrapper dar&#xfc;ber"/>
<node CREATED="1697156077365" ID="ID_1535123758" MODIFIED="1697156103949" TEXT="Zus&#xe4;tzlich Erg&#xe4;nzung um eine TryLock-Variante (als optional&lt;Guard&gt;)"/>
</node>
</node>
<node CREATED="1697156128590" ID="ID_731556592" MODIFIED="1697156131743" TEXT="Abw&#xe4;gung">
<node CREATED="1697156137517" ID="ID_817522107" MODIFIED="1697156191121" TEXT="der &#xbb;transparente Switch&#xab; ist rasch und ohne Risiko umsetzbar">
<node 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"/>
<node CREATED="1697156412448" ID="ID_659475954" MODIFIED="1697156527005" TEXT="das Ergebnis ist offen f&#xfc;r &#x201e;wilden&#x201c; Direkt-Gebrauch">
<node CREATED="1697156532544" ID="ID_273574678" MODIFIED="1697156637966" TEXT="denn urspr&#xfc;nglich war das sogar die Intention">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Ganz am Anfang hatte ich die Makros aus NoBug, deren Gebrauch im C++-Code schwierig ist. Daher dachte ich, ich packe die jeweils in einen Wrapper. Der Monitor ist dann nur ein Zustatz-Feature
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1697156544607" ID="ID_1900999328" MODIFIED="1697156780356" TEXT="solcher Gebrauch ist dann aber in der Praxis bisher nie notwendig gewesen">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...aber nachdem ich den Monitor entwickelt hatte, war mir klar, da&#223; ich an den Basis-Elementen gar kein Interesse mehr habe, weil der Monitor ein Design-Pattern ist und damit ordnend auf den Code wirkt. Im Lauf der Jahre hat sich dann gezeigt, da&#223; ich &#252;berhaupt nichts anderes brauche, als nur das Lock-Guard front-End (+Atomics f&#252;r alle nicht-trivialen F&#228;lle).
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1697156786102" ID="ID_1309147992" MODIFIED="1697156842803" TEXT="die C++ Wrapper allerdings machen &#x201e;wilden&#x201c; Gebrauch unattraktiv und unwahrscheinlich"/>
</node>
<node CREATED="1697156922980" ID="ID_1251565315" MODIFIED="1697156937622" TEXT="das Ergebnis stellt aber keine strukturelle Verschlechterung dar"/>
<node CREATED="1697156941858" ID="ID_933669206" MODIFIED="1697156948146" TEXT="...und k&#xf6;nnte daher ein Zwischenschritt sein"/>
</node>
<node CREATED="1697156852566" ID="ID_1056176020" MODIFIED="1697156881277" TEXT="die &#xbb;strukturelle Verbesserung&#xab; stellt l&#xe4;ngerfristig das Minimum an Code-Qualit&#xe4;t dar">
<node CREATED="1697156959663" ID="ID_1687873684" MODIFIED="1697156975190" TEXT="da klar ist, da&#xdf; nur der Monitor verwendet werden soll..."/>
<node CREATED="1697156976195" ID="ID_681854744" MODIFIED="1697156985008" TEXT="deshalb kann auch alles Andere zur&#xfc;ckgebaut werden"/>
<node CREATED="1697157070044" ID="ID_1501146985" MODIFIED="1697157223059" TEXT="die unique_lock-Instanz ist zugleich Verbesserung und zus&#xe4;tzlicher Ballast">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Verbesserung, weil sie die Implementierung einfach und klar macht, und mehr dem C++-Stil entspricht. Aber sie ist auch ein stets vorhandener zus&#228;tzlicher Storage-Ballast, der eigentlich nicht notwendig w&#228;re
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1697157236623" ID="ID_1796494876" MODIFIED="1697157269817" TEXT="die Implementierung im Monitor m&#xfc;&#xdf;te schrittweise aufgebaut/konsolidiert werden"/>
<node CREATED="1697157270541" ID="ID_1316555147" MODIFIED="1697157286077" TEXT="dazu sollte vorher f&#xfc;r ausreichende Test-Coverage gesorgt sein"/>
</node>
<node CREATED="1697157349262" ID="ID_871141135" MODIFIED="1697157367972" TEXT="das &#xbb;Monitor-Refactoring&#xab; entspricht meinem eigenen Qualit&#xe4;ts-Anspruch">
<node CREATED="1697157372112" ID="ID_247839273" MODIFIED="1697157389225" TEXT="das bedeutet: l&#xe4;ngerfristig sollte das das Ziel sein"/>
<node CREATED="1697157390189" ID="ID_1494264417" MODIFIED="1697157417062" TEXT="Nachteil: es ist ein Privat-Konzept und theoretisch nicht untersucht"/>
<node CREATED="1697157432440" ID="ID_30899784" MODIFIED="1697157455160" TEXT="es w&#xfc;rde das Ballast-Problem der mittleren Variante beheben"/>
<node CREATED="1697157469806" ID="ID_1885906639" MODIFIED="1697157489020" TEXT="das Ausarbeiten eines sinnvollen Proze&#xdf;-API braucht Zeit und Experimente"/>
</node>
</node>
<node COLOR="#435e98" CREATED="1697157515644" ID="ID_91141549" MODIFIED="1697157775531" TEXT="Fazit">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="forward"/>
<node CREATED="1697157519076" ID="ID_319583115" MODIFIED="1697157532140" TEXT="es handelt sich nicht um Alternativen, sondern einen Stufen-Plan"/>
<node CREATED="1697157566462" ID="ID_652673137" MODIFIED="1697157722839" TEXT="zur Vermeidung von Entwicklungs-Risiken sollten alle Schritte durchlaufen werden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
zwar traue ich mir zu, die mittlere Stufe der &#187;strukturellen Verbesserung&#171; direkt zu implementieren, aber in dieser Hinsicht &#252;bersch&#228;tze ich h&#228;ufig die reale Komplexit&#228;t und die Projekt-Risiken. Schon allein um aufwendige Regressionen zu vermeiden sollte stets auf gute Test-Coverage geachtet werden, was nurch durch schritweises Vorgehen m&#246;glich ist
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1697157736647" ID="ID_1786481655" MODIFIED="1697157768097" TEXT="da ich unter Zeitdruck stehe, ist es denkbar, zun&#xe4;chst nur die erste Stufe umzusetzen"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696538492114" ID="ID_1214186481" MODIFIED="1696538497123" TEXT="Umarbeiten">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1697208267170" ID="ID_1417792791" MODIFIED="1697208273283" TEXT="Stufe-1">
<icon BUILTIN="pencil"/>
<node CREATED="1697211709960" ID="ID_1334084058" MODIFIED="1697211722231" TEXT="mutex, shared_mutex und condition_var_any einf&#xfc;hren"/>
<node CREATED="1697212577546" ID="ID_701908821" MODIFIED="1697212604297" TEXT="elementare Wait-Logik in wrapped_condition nachbauen">
<node CREATED="1697212819465" ID="ID_1989441029" MODIFIED="1697212843810" TEXT="die Timeout-Flag wird hintenrum durch lumiera_lockerror hochgegeben">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1697212844861" ID="ID_1361936196" MODIFIED="1697212864910" TEXT="aber die n&#xe4;chste Ebene in Condition::wait() setzt das bereits in einen bool um"/>
<node CREATED="1697212907981" ID="ID_1359746473" MODIFIED="1697212958572" TEXT="ebenso wird die Timeout-Zeit im Monitor in einen ulong(millis) umgesetzt"/>
</node>
<node CREATED="1697212978323" ID="ID_1878302471" MODIFIED="1697213004811" TEXT="also sollte den &#xbb;timeout&#xab; sofort modernisieren">
<node CREATED="1697226451516" ID="ID_1234718286" MODIFIED="1697226471469" TEXT="erst mal auf Millisekunden-Parameter, der 0 sein kann"/>
<node CREATED="1697226473433" ID="ID_1085819281" MODIFIED="1697226495115" TEXT="brauche keine Klasse Timeout mehr, die einen Timeout fest speichert"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697226910607" ID="ID_1996109798" MODIFIED="1697226924118" TEXT="bisher gab es das Konzept isTimedWait()">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1697227170044" ID="ID_1914088992" MODIFIED="1697227366621" TEXT="der Subsystem-Runner verwendet das (einzige Verwendung)"/>
<node CREATED="1697227176603" ID="ID_1461108141" MODIFIED="1697227196532" TEXT="er kann im Emergency-Fall nachtr&#xe4;glich ein Timeout setzen"/>
<node CREATED="1697227368355" ID="ID_8720299" MODIFIED="1697227492130" TEXT="vermeidet Deadlock mit nur einem Thread">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...zumindest war das wohl die Motivation, wenn ich die Kommentare im Test hinzunehme.
</p>
</body>
</html>
</richcontent>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1697227493003" ID="ID_1899195103" MODIFIED="1697227520087" TEXT="erscheint mir halbgar">
<icon BUILTIN="smiley-angry"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697229575552" ID="ID_756306663" MODIFIED="1697232150319" TEXT="saubere L&#xf6;sung">
<arrowlink COLOR="#4b4593" DESTINATION="ID_1987547541" ENDARROW="Default" ENDINCLINATION="-595;-40;" ID="Arrow_ID_1122128450" STARTARROW="None" STARTINCLINATION="-613;91;"/>
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1697226501663" ID="ID_1038438154" MODIFIED="1697226512124" TEXT="Problem Kopierbarkeit">
<icon BUILTIN="flag-pink"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1697226517446" ID="ID_1311077272" MODIFIED="1697226570220" TEXT="Monitor hat das Problem bisher verborgen">
<arrowlink COLOR="#c36885" DESTINATION="ID_1383871199" ENDARROW="Default" ENDINCLINATION="-768;38;" ID="Arrow_ID_1367033811" STARTARROW="None" STARTINCLINATION="-220;-13;"/>
<icon BUILTIN="info"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697238392317" ID="ID_785406259" MODIFIED="1697238398404" TEXT="Stufe-2">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1697238399214" ID="ID_38924085" MODIFIED="1697238402259" TEXT="Stufe-3">
<icon BUILTIN="hourglass"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1697212016574" ID="ID_567956121" MODIFIED="1697212026079" TEXT="R&#xfc;ckbau">
<icon BUILTIN="hourglass"/>
<node CREATED="1697212020164" ID="ID_69317330" MODIFIED="1697212022087" TEXT="POSIX"/>
<node CREATED="1697212022651" ID="ID_1532773678" MODIFIED="1697212023483" TEXT="lumiera_lockerror_set"/>
<node CREATED="1697213046906" ID="ID_1074499968" MODIFIED="1697213052317" TEXT="timespec und clock_gettime"/>
</node>
</node>
</node>
</node>
@ -66536,6 +66860,96 @@
</node>
</node>
</node>
<node CREATED="1697229705261" ID="ID_764850645" MODIFIED="1697229713192" TEXT="Steuerung der Subsysteme">
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1697229736548" ID="ID_327697277" MODIFIED="1697229753890" TEXT="Entwicklung Subsystem-Konzept">
<icon BUILTIN="hourglass"/>
<node CREATED="1697229756390" ID="ID_1054796650" MODIFIED="1697230627356" TEXT="erster Wurf seit vielen Jahren im Einsatz">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...hatte ich damals sehr schnell geschrieben, um zu zeigen da&#223; eine C++ - L&#246;sung auch &#187;einfach&#171; sein kann. Chistian wollte damals unbedingt die Application-main in C implementieren, &#8222;damit alles wirklich einfach und verst&#228;ndlich bleibt&#8220;. Ich hatte das Gef&#252;hl, da stand eine Agenda im Raum, da&#223; alles Wichtige in C sein sollte. Ich vertrat (und vertrete bis heute) den Standpunkt, da&#223; die Erweiterungen in C++ aus gutem Grunde geschaffen wurden, weil C in wesentlichen Aspekten mutwillig zu einfach gehalten ist. F&#252;r den Traum von der <i>sch&#246;nen einfachen L&#246;sung</i>&#160;zahlt man dann jeden Tag Zinsen f&#252;r technische Schulden.
</p>
</body>
</html></richcontent>
<icon BUILTIN="smiley-oh"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697230306599" ID="ID_1415549362" MODIFIED="1697230637141" TEXT="Kritik an der ersten Version des Konzepts">
<icon BUILTIN="broken-line"/>
<node CREATED="1697230653730" ID="ID_777823460" MODIFIED="1697230691378">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
sie erf&#252;llt alle Anforderungen, ist aber <i>zu sehr vereinfacht</i>
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1697230694524" ID="ID_939615565" MODIFIED="1697230717045" TEXT="der Subsystem-Lebenszyklus setzt zu stark auf Konventionen"/>
<node CREATED="1697230726208" ID="ID_1811646071" MODIFIED="1697231115768" TEXT="es fehlen &#xdc;bergangs-Zust&#xe4;nde, die in der Realit&#xe4;t eben auftreten">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Vor allem...
</p>
<ul>
<li>
ein Subsystem ist nicht einfach <i>gestartet </i>oder <i>nicht-gestartet. </i>Vielmehr ist der Start zun&#228;chst <i>initiiert, </i>und nach Erf&#252;llung lokaler Kriterien ist der Start <i>vollst&#228;ndig.</i>
</li>
<li>
entsprechend ist ein Subsystem nicht einfach <i>gestoppt. </i>Vielmehr ist <i>der Shutdown-angek&#252;ndigt, </i>dann die <i>aktive-Phase-verlassen </i>und schlie&#223;lich der <i>shutdown-abgeschlossen.</i>
</li>
</ul>
</body>
</html></richcontent>
</node>
<node CREATED="1697231128386" ID="ID_148831636" MODIFIED="1697231157458" TEXT="bedingt dadurch wird die Fehlerbehandlung extrem komplex und br&#xfc;chig"/>
<node CREATED="1697231166101" ID="ID_1734528491" MODIFIED="1697231545488" TEXT="die Bedeutung des &#xbb;emergency Shutdown&#xab; ist nicht gekl&#xe4;rt">
<arrowlink COLOR="#fdfbae" DESTINATION="ID_1349710577" ENDARROW="Default" ENDINCLINATION="-59;-2;" ID="Arrow_ID_1841665742" STARTARROW="None" STARTINCLINATION="-62;3;"/>
</node>
</node>
<node CREATED="1697231321617" ID="ID_1987547541" MODIFIED="1697232150319" TEXT="&#xdc;berarbeitung &#xbb;Emergency-Shutdown&#xab;">
<linktarget COLOR="#4b4593" DESTINATION="ID_1987547541" ENDARROW="Default" ENDINCLINATION="-595;-40;" ID="Arrow_ID_1122128450" SOURCE="ID_756306663" STARTARROW="None" STARTINCLINATION="-613;91;"/>
<node 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"/>
<node CREATED="1697231438932" ID="ID_1169428609" MODIFIED="1697231453874" TEXT="normalerweise wird beliebig lange gewartet"/>
<node CREATED="1697231455104" ID="ID_330146897" MODIFIED="1697231479415" TEXT="Application-main wird erst verlassen, wenn alle Subsysteme sich abgemeldet haben"/>
<node CREATED="1697231502864" ID="ID_903747246" MODIFIED="1697231589888" TEXT="Fehlerausgang aus einem Subsystem &#x27f9; Heuristik f&#xfc;r korrumpiertes Gesamtsystem"/>
<node CREATED="1697231841691" ID="ID_480459566" MODIFIED="1697231861116" TEXT="daher bei Emergency die Wartezeit begrenzen (und Folgefehler in Kauf nehmen)"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1697231867607" ID="ID_894790570" MODIFIED="1697232116770" TEXT="durch einen Trick im Object-Monitor implementiert">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
In lib::Sync (genauer: in der Implementierung Monitor-wait) war eine Unterst&#252;tzung f&#252;r Timeout nach POSIX eingebaut worden. Dies erfordert, da&#223; die Timeout-Spec in der Storage des Client bereitgehalten wird (weil man POSIX-Funktionen nur einen Pointer &#252;bergibt). Das habe ich hierf&#252;r ausgen&#252;tzt, indem nachtr&#228;glich, im Fall einer Emergency, noch ein Timeout definiert wird. Da Condition-Variablen zur Pr&#252;fung der Bedingung immer wieder aufgeweckt werden, kann man so nachtr&#228;glich eine Art vorzeitigen Abbruch realisieren...
</p>
</body>
</html></richcontent>
</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>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697231265769" ID="ID_28627055" MODIFIED="1697231276175" TEXT="Subsystem-Definition">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1697231270063" ID="ID_1888527843" MODIFIED="1697231276175" TEXT="Subsystem-Runner">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
</node>
<node CREATED="1482524498822" ID="ID_431883229" MODIFIED="1557498707236" TEXT="Datenstrom">