Library: test coverage for self-managed thread
...extract and improve the tuple-rewriting function ...improve instance tracking test dummy objects ...complete test coverage and verify proper memory handling
This commit is contained in:
parent
f6a6b0b68f
commit
7b25609896
9 changed files with 449 additions and 113 deletions
|
|
@ -205,6 +205,54 @@ namespace meta{
|
|||
|
||||
|
||||
|
||||
/** Placeholder marker for a special argument position to be supplied later */
|
||||
template<class TAR>
|
||||
struct InstancePlaceholder { };
|
||||
|
||||
namespace {// Helper to inject instance-pointer instead of placeholder...
|
||||
/**
|
||||
* @internal helper to detect an InstancePlaceholder
|
||||
* @return an instance-pointer, statically casted to the marked target type.
|
||||
*/
|
||||
template<class W, class TAR>
|
||||
constexpr inline TAR*
|
||||
maybeInject (W& instance, InstancePlaceholder<TAR>)
|
||||
{
|
||||
return static_cast<TAR*> (&instance);
|
||||
}
|
||||
|
||||
/** (default case: fall-through) */
|
||||
template<class W, typename X>
|
||||
constexpr inline X
|
||||
maybeInject (W&, X&& x)
|
||||
{
|
||||
return std::move(x);
|
||||
}
|
||||
}//(End)Helper for lateBindInstance.
|
||||
|
||||
/**
|
||||
* Fix-up the arguments for a member-function invocation,
|
||||
* allowing to inject the actual `this` instance into an existing argument sequence.
|
||||
* @remark invocation of a member function requires to supply the _object instance_ as
|
||||
* first element in the argument list; sometimes this poses a design challenge,
|
||||
* since the actual instance may not be known at the point where the other arguments
|
||||
* are prepared. As a remedy, the position of the instance pointer can be marked with
|
||||
* the \ref InstancePlaceholder, allowing to splice in the actual pointer when known.
|
||||
*/
|
||||
template<class W, class TUP>
|
||||
constexpr inline auto
|
||||
lateBindInstance (W& instance, TUP&& invocation)
|
||||
{
|
||||
auto splice = [&instance](auto&& ...xs)
|
||||
{
|
||||
return std::tuple{maybeInject (instance, std::move(xs))...};
|
||||
};
|
||||
return std::apply (splice, std::forward<TUP> (invocation));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -214,7 +262,7 @@ namespace meta{
|
|||
* and the bare function signature #Sig
|
||||
* @param RET the function return type
|
||||
* @param ARGS a type sequence describing the arguments
|
||||
*/
|
||||
*/ //////////////////////////////////////////////////////////////////////TICKET #987 : make lib::meta::Types<TYPES...> variadic, then replace this by a single variadic template
|
||||
template<typename RET, typename ARGS>
|
||||
struct FunctionTypedef;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ namespace test{
|
|||
long Dummy::_local_checksum = 0;
|
||||
bool Dummy::_throw_in_ctor = false;
|
||||
|
||||
EventLog Tracker::log{"Instance-Tracker"};
|
||||
|
||||
|
||||
|
||||
string
|
||||
|
|
|
|||
|
|
@ -22,23 +22,32 @@
|
|||
|
||||
|
||||
/** @file testdummy.hpp
|
||||
** unittest helper code: test dummy object.
|
||||
** This dummy includes some distinct random identity marker
|
||||
** plus a checksum facility to verify instance management, i.e.
|
||||
** to verify each created instance was properly destroyed after use.
|
||||
** unittest helper code: test dummy objects to track instances.
|
||||
** These can be used to verify proper allocation handling, either by
|
||||
** watching the checksum of \ref Dummy, or by matching on the \ref EventLog
|
||||
** embedded into \ref Tracker.
|
||||
*/
|
||||
|
||||
|
||||
#include "lib/nocopy.hpp"
|
||||
#include "lib/test/event-log.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace test{
|
||||
|
||||
|
||||
class Dummy
|
||||
|
||||
/**
|
||||
* A Dummy object for tests. Each instance includes some distinct
|
||||
* random identity marker plus a checksum facility to verify instance management,
|
||||
* i.e. to verify each created instance was properly destroyed after use.
|
||||
*/
|
||||
class Dummy
|
||||
: util::NonCopyable
|
||||
{
|
||||
int val_;
|
||||
|
|
@ -62,6 +71,7 @@ namespace test{
|
|||
}
|
||||
|
||||
virtual long
|
||||
|
||||
acc (int i) ///< dummy API operation
|
||||
{
|
||||
return val_+i;
|
||||
|
|
@ -107,8 +117,100 @@ namespace test{
|
|||
if (_throw_in_ctor)
|
||||
throw val_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A tracking Dummy object for tests.
|
||||
* All construction-, destruction and copy operations
|
||||
* are logged into an embedded lib::test::EventLog
|
||||
*/
|
||||
struct Tracker
|
||||
{
|
||||
static lib::test::EventLog log;
|
||||
|
||||
static constexpr int DEFUNCT = std::numeric_limits<int>::min();
|
||||
static constexpr int DEAD = std::numeric_limits<int>::max();
|
||||
|
||||
int val;
|
||||
|
||||
~Tracker()
|
||||
{
|
||||
log.call (this,"dtor", val);
|
||||
val = DEAD;
|
||||
}
|
||||
|
||||
Tracker()
|
||||
: val{rand() % 1000}
|
||||
{
|
||||
log.call (this,"ctor");
|
||||
}
|
||||
|
||||
Tracker(int v)
|
||||
: val{v}
|
||||
{
|
||||
log.call (this,"ctor", v);
|
||||
}
|
||||
|
||||
Tracker(Tracker const& ol)
|
||||
: val{ol.val}
|
||||
{
|
||||
log.call (this,"ctor-copy", ol);
|
||||
}
|
||||
|
||||
Tracker(Tracker && oo)
|
||||
: val{oo.val}
|
||||
{
|
||||
log.call (this,"ctor-move", oo);
|
||||
oo.val = DEFUNCT;
|
||||
}
|
||||
|
||||
Tracker&
|
||||
operator= (Tracker const& ol)
|
||||
{
|
||||
if (util::isSameObject (*this, ol))
|
||||
{
|
||||
log.call (this, "self-assign-copy");
|
||||
}
|
||||
else
|
||||
{
|
||||
log.call (this, "assign-copy", ol);
|
||||
val = ol.val;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Tracker&
|
||||
operator= (Tracker && oo)
|
||||
{
|
||||
if (util::isSameObject (*this, oo))
|
||||
{
|
||||
log.call (this, "self-assign-move");
|
||||
}
|
||||
else
|
||||
{
|
||||
log.call (this, "assign-move", oo);
|
||||
val = oo.val;
|
||||
oo.val = DEFUNCT;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator string() const
|
||||
{
|
||||
return util::_Fmt{"Track{%02d}"} % val;
|
||||
}
|
||||
|
||||
friend void
|
||||
swap (Tracker& t1, Tracker& t2)
|
||||
{
|
||||
log.call ("static", "swap", t1, t2);
|
||||
std::swap (t1.val, t2.val);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
|
|
|||
|
|
@ -150,6 +150,7 @@ namespace lib {
|
|||
|
||||
namespace thread {// Thread-wrapper base implementation...
|
||||
|
||||
using lib::meta::lateBindInstance;
|
||||
using lib::meta::typeSymbol;
|
||||
using lib::meta::_Fun;
|
||||
using util::isnil;
|
||||
|
|
@ -360,27 +361,6 @@ namespace lib {
|
|||
}
|
||||
};
|
||||
|
||||
template<class TAR>
|
||||
struct InstancePlaceholder { };
|
||||
|
||||
template<class W, class INVO>
|
||||
inline INVO
|
||||
lateBindInstance (W&, INVO invocation)
|
||||
{
|
||||
return invocation;
|
||||
}
|
||||
|
||||
template<class W, class F, class TAR, typename...ARGS>
|
||||
inline auto
|
||||
lateBindInstance (W& instance, const tuple<F, InstancePlaceholder<TAR>, ARGS...> invocation)
|
||||
{
|
||||
auto splice = [&instance](auto f, auto&, auto ...args)
|
||||
{
|
||||
TAR* instancePtr = static_cast<TAR*> (&instance);
|
||||
return tuple{move(f), instancePtr, move(args)...};
|
||||
};
|
||||
return std::apply (splice, invocation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Policy-based configuration of thread lifecycle
|
||||
|
|
@ -784,7 +764,7 @@ namespace lib {
|
|||
{
|
||||
using Launch = typename TAR::Launch;
|
||||
launchDetached<TAR> (Launch{std::move (memFun)
|
||||
,thread::InstancePlaceholder<TAR>{}
|
||||
,lib::meta::InstancePlaceholder<TAR>{}
|
||||
,forward<ARGS> (args)...
|
||||
}
|
||||
.threadID (threadID));
|
||||
|
|
@ -795,10 +775,10 @@ namespace lib {
|
|||
inline void
|
||||
launchDetached (void (TAR::*memFun) (ARGS...), ARGS ...args)
|
||||
{
|
||||
return launchDetached (util::joinDash (lib::meta::typeSymbol<TAR>(), args...)
|
||||
,memFun
|
||||
,forward<ARGS> (args)...
|
||||
);
|
||||
launchDetached (util::joinDash (lib::meta::typeSymbol<TAR>(), args...)
|
||||
,memFun
|
||||
,forward<ARGS> (args)...
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
PLANNED "Launch self-contained detached Thread" ThreadWrapperAutonomous_test <<END
|
||||
TEST "Launch self-contained detached Thread" ThreadWrapperAutonomous_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
|
|
|||
|
|
@ -238,6 +238,11 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "member function late binding" LateBindInstance_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "metaprogramming helpers" MetaUtils_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
|
|
|||
196
tests/library/meta/late-bind-instance-test.cpp
Normal file
196
tests/library/meta/late-bind-instance-test.cpp
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
LateBindInstance(Test) - verify rewriting of member function invocation
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2023, 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 late-bind-instance-test.cpp
|
||||
** unit test \ref LateBindInstance_test
|
||||
*/
|
||||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/meta/function.hpp"
|
||||
#include "lib/meta/tuple-helper.hpp"
|
||||
#include "lib/test/testdummy.hpp"
|
||||
#include "lib/format-cout.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "lib/test/diagnostic-output.hpp"
|
||||
#include "lib/rational.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
namespace test {
|
||||
|
||||
using std::move;
|
||||
using std::rand;
|
||||
using std::tuple;
|
||||
using std::string;
|
||||
using lib::meta::dump;
|
||||
using lib::test::Tracker;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************//**
|
||||
* @test verify a scheme to supply the actual instance for member function invocation.
|
||||
* @remark in the end this is just a value replacement in a tuple, where the position
|
||||
* is marked with a placeholder type. This scheme is used for starting threads,
|
||||
* where the actual thread instance is not known yet at the point where the
|
||||
* arguments for the thread-function are constructed
|
||||
* @see lib::launchDetached
|
||||
*/
|
||||
class LateBindInstance_test : public Test
|
||||
{
|
||||
void
|
||||
run (Arg)
|
||||
{
|
||||
demonstrateUsage();
|
||||
verify_forwarding();
|
||||
verify_cornerCases();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test demonstrate the usage of lib::meta::lateBindInstance():
|
||||
* - construct an argument tuple
|
||||
* - mark the position of the `this`-ptr with a placeholder
|
||||
* - rewrite the arguments later when the actual instance is known
|
||||
* - member function can now be invoked, since the instance was injected.
|
||||
*/
|
||||
void
|
||||
demonstrateUsage()
|
||||
{
|
||||
uint randomLimit = 2 + rand() % 98;
|
||||
|
||||
auto plannedArgs
|
||||
= tuple{InstancePlaceholder<LateBindInstance_test>{}
|
||||
,randomLimit
|
||||
};
|
||||
|
||||
// the actual instance may be available only later...
|
||||
Test& instanceRef = *this;
|
||||
|
||||
// now rewrite the argument tuple to inject the instance-ptr
|
||||
auto preparedArgs = lateBindInstance (instanceRef, plannedArgs);
|
||||
|
||||
uint res = std::apply (&LateBindInstance_test::theMember, preparedArgs);
|
||||
CHECK (res < randomLimit);
|
||||
}
|
||||
|
||||
uint
|
||||
theMember (uint limit)
|
||||
{
|
||||
return rand() % limit;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test verify that the rewriting process does not incur unnecessary data copies
|
||||
*/
|
||||
void
|
||||
verify_forwarding()
|
||||
{
|
||||
auto& log = Tracker::log;
|
||||
log.clear (this);
|
||||
|
||||
InstancePlaceholder<LateBindInstance_test> marker;
|
||||
Tracker t1(11);
|
||||
|
||||
log.event("construct tuple");
|
||||
tuple tup(t1, marker, Tracker{23}, 55);
|
||||
|
||||
Test& instanceRef = *this;
|
||||
|
||||
log.event("invoke lateBindInstance");
|
||||
auto tup1r = lateBindInstance (instanceRef, tup);
|
||||
log.event("got result");
|
||||
|
||||
// before invocation the Tracker instances are created (obviously..)
|
||||
CHECK (log.verifyCall("ctor").arg(11)
|
||||
.beforeCall("ctor-copy").arg("Track{11}")
|
||||
.beforeEvent("invoke lateBindInstance"));
|
||||
CHECK (log.verifyCall("ctor").arg(23)
|
||||
.beforeCall("ctor-move").arg("Track{23}")
|
||||
.beforeCall("dtor").arg(Tracker::DEFUNCT)
|
||||
.beforeEvent("invoke lateBindInstance"));
|
||||
|
||||
// but there is no copy operation after the invocation
|
||||
CHECK (log.ensureNot("ctor-copy")
|
||||
.afterEvent("invoke lateBindInstance"));
|
||||
|
||||
// both Tracker instances are moved two times
|
||||
// - once to create the maybeInject-invocation and
|
||||
// - once to consolidate the result
|
||||
// for each instance one moved-away temporary is destroyed
|
||||
CHECK (log.verifyEvent("invoke lateBindInstance")
|
||||
.beforeCall("ctor-move").arg("Track{11}")
|
||||
.beforeCall("ctor-move").arg("Track{11}")
|
||||
.beforeCall("dtor").arg(Tracker::DEFUNCT)
|
||||
.beforeEvent("got result"));
|
||||
CHECK (log.verifyEvent("invoke lateBindInstance")
|
||||
.beforeCall("ctor-move").arg("Track{23}")
|
||||
.beforeCall("ctor-move").arg("Track{23}")
|
||||
.beforeCall("dtor").arg(Tracker::DEFUNCT)
|
||||
.beforeEvent("got result"));
|
||||
|
||||
cout << "____Tracker-Log_______________\n"
|
||||
<< util::join(Tracker::log, "\n")
|
||||
<< "\n───╼━━━━━━━━━━━╾──────────────"<<endl;
|
||||
}
|
||||
|
||||
|
||||
/** @test replacement happens uniformely on all kinds of tuples
|
||||
*/
|
||||
void
|
||||
verify_cornerCases()
|
||||
{
|
||||
long dummy{555};
|
||||
InstancePlaceholder<long> marker;
|
||||
CHECK (dump(lateBindInstance (dummy, tuple<>{})) == "()"_expect);
|
||||
CHECK (dump(lateBindInstance (dummy, tuple{42})) == "(42)"_expect);
|
||||
CHECK (dump(lateBindInstance (dummy, tuple{1,2,3})) == "(1,2,3)"_expect);
|
||||
CHECK (dump(lateBindInstance (dummy, tuple{marker,2,3})) == "(«long»,2,3)"_expect);
|
||||
CHECK (dump(lateBindInstance (dummy, tuple{1,marker,3})) == "(1,«long»,3)"_expect);
|
||||
CHECK (dump(lateBindInstance (dummy, tuple{1,2,marker})) == "(1,2,«long»)"_expect);
|
||||
CHECK (dump(lateBindInstance (dummy, tuple{marker})) == "(«long»)"_expect);
|
||||
CHECK (dump(lateBindInstance (dummy, tuple{string{"1"}
|
||||
,"2"
|
||||
,marker
|
||||
,tuple(2,3)
|
||||
, 5.5
|
||||
})) == "(1,2,«long»,«tuple<int, int>»──(2,3),5.5)"_expect);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (LateBindInstance_test, "unit meta");
|
||||
|
||||
|
||||
|
||||
}}} // namespace lib::meta::test
|
||||
|
|
@ -28,26 +28,18 @@
|
|||
#include "lib/test/run.hpp"
|
||||
#include "lib/test/testdummy.hpp"
|
||||
#include "lib/thread.hpp"
|
||||
#include "lib/test/diagnostic-output.hpp"///////////////////TODO
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
|
||||
using test::Test;
|
||||
using std::atomic_uint;
|
||||
using std::this_thread::yield;
|
||||
using std::atomic_bool;
|
||||
using std::this_thread::sleep_for;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace test{
|
||||
|
||||
namespace { // test parameters
|
||||
|
||||
const uint NUM_THREADS = 200;
|
||||
const uint REPETITIONS = 10;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************//**
|
||||
|
|
@ -71,11 +63,11 @@ namespace test{
|
|||
void
|
||||
demonstrateSimpleUsage()
|
||||
{
|
||||
atomic_uint i{0};
|
||||
launchDetached ("anarchy", [&]{ ++i; });
|
||||
atomic_bool didRun{false};
|
||||
launchDetached ("anarchy", [&]{ didRun = true; });
|
||||
|
||||
sleep_for(1ms);
|
||||
CHECK (i == 1); // verify the effect has taken place
|
||||
CHECK (didRun); // verify the effect has taken place
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -96,17 +88,17 @@ namespace test{
|
|||
doIt (int extra)
|
||||
{
|
||||
watcher.setVal (extra);
|
||||
SHOW_EXPR(extra)
|
||||
sleep_for (5ms);
|
||||
SHOW_EXPR("bye")
|
||||
}
|
||||
};
|
||||
//
|
||||
// Note the Dummy member allows to watch instance lifecycle
|
||||
CHECK (0 == Dummy::checksum());
|
||||
//
|
||||
|
||||
launchDetached<TestThread> (&TestThread::doIt, 55);
|
||||
|
||||
CHECK (0 < Dummy::checksum());
|
||||
sleep_for (1ms);
|
||||
CHECK (55 == Dummy::checksum());
|
||||
sleep_for (10ms);
|
||||
CHECK (0 == Dummy::checksum());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65187,7 +65187,7 @@
|
|||
</node>
|
||||
<node COLOR="#435e98" CREATED="1696529645817" ID="ID_461966137" MODIFIED="1696966078558" TEXT="Varianten/Weiterungen">
|
||||
<icon BUILTIN="list"/>
|
||||
<node CREATED="1696529655008" ID="ID_1683255981" MODIFIED="1696529699438" TEXT="Variante-1 : self-managed">
|
||||
<node COLOR="#435e98" CREATED="1696529655008" ID="ID_1683255981" MODIFIED="1697050739549" TEXT="Variante-1 : self-managed">
|
||||
<node CREATED="1696529705915" ID="ID_731698797" MODIFIED="1696532569698" TEXT="in der Policy liegt ein unique_ptr">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
|
|
@ -65348,13 +65348,12 @@
|
|||
</node>
|
||||
<node CREATED="1696965973496" ID="ID_1562329556" MODIFIED="1696965986393" TEXT="und eine sonderbare spezial-Policy fällt komplett weg"/>
|
||||
<node CREATED="1696965999636" ID="ID_1837122164" MODIFIED="1696966015867" TEXT="es gibt keine spezielle Thread-Klasse mehr, die man »nicht verwenden« soll"/>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1696976539898" ID="ID_57182560" MODIFIED="1696976562311" TEXT="ABER: kann mit diesem Design keine Member-Funktionen in den Thread binden">
|
||||
<node COLOR="#435e98" CREATED="1696976539898" ID="ID_57182560" MODIFIED="1697050703737" TEXT="ABER: kann mit diesem Design keine Member-Funktionen in den Thread binden">
|
||||
<linktarget COLOR="#5d6faa" DESTINATION="ID_57182560" ENDARROW="Default" ENDINCLINATION="-230;791;" ID="Arrow_ID_1090153547" SOURCE="ID_92765841" STARTARROW="None" STARTINCLINATION="772;-34;"/>
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696976568054" ID="ID_1651696265" MODIFIED="1696976852099" TEXT="das macht abgeleitete Klassen effektiv sinnlos">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
denn: grade hier für den »Autonomous Thread« kommt man von außen nicht an die Addresse des Objektes ran
|
||||
|
|
@ -65371,60 +65370,50 @@
|
|||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<linktarget COLOR="#f73362" DESTINATION="ID_1651696265" ENDARROW="Default" ENDINCLINATION="-61;-30;" ID="Arrow_ID_120849360" SOURCE="ID_1670280316" STARTARROW="None" STARTINCLINATION="283;19;"/>
|
||||
</node>
|
||||
<node CREATED="1696976853336" ID="ID_372976819" MODIFIED="1696976877733" TEXT="das führt die Idee mit einer selbst-verwalteten Allokation ad absurdum">
|
||||
<icon BUILTIN="smiley-angry"/>
|
||||
</node>
|
||||
<node CREATED="1696976940356" ID="ID_232121625" MODIFIED="1696977061323" TEXT="hier rächt sich auch das »Zwiebelschalen-Design«: der Launch-builder ist opaque"/>
|
||||
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1696978145159" ID="ID_314579443" MODIFIED="1696978153755" TEXT="gibt es überhaupt einen Fix?">
|
||||
<node COLOR="#435e98" CREATED="1696978145159" ID="ID_314579443" MODIFIED="1697050413021" TEXT="gibt es überhaupt einen Fix?">
|
||||
<icon BUILTIN="help"/>
|
||||
<node COLOR="#5b280f" CREATED="1696978155858" ID="ID_229604383" MODIFIED="1696978809501" TEXT="übler Hack: Fake-Allokation + placement-New">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Wenn wir es irgendwie schaffen könnten, das Objekt schon auf den Heap zu allozieren, aber zu verhindern, daß es „fliegt“ (bzw. wirklich konstruiert wird). Dann wüßten wir die Addresse. Danach würden wir ein placement-New in die Allokation machen, und könnten diesem <i>tatsächlichen </i>Konstruktor-Aufruf <i>ganz verträumt </i>den richtigen Instanz-Pointer mitgeben. Vorraussetzung wäre allerdings, daß sich diese manipulierte Allokation später ganz gewöhnlich per operator delete wieder entfernen ließe. Das wäre dann entweder ein fragiler Hack, der sich auf Plattform-Interna abstützt, oder es wäre ein custom-operator-new im Stil der 90er-Jahre
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="closed"/>
|
||||
</node>
|
||||
<node CREATED="1696978523249" ID="ID_1356286451" MODIFIED="1697023022905" TEXT="einen Platzhalter spät an die eigentliche Instanz binden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Daf&#252;r br&#228;uchte ich eine Stelle, an der die tats&#228;chliche Instanz bereits
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Dafür bräuchte ich eine Stelle, an der die tatsächliche Instanz bereits
|
||||
bekannt ist, aber die Invocation nochin generischer Form vorliegt. In
|
||||
einem solchen Kontext k&#246;nnte man dann einen Marker-Typ erkennen und an
|
||||
die tats&#228;chliche Instanz binden.
|
||||
</p>
|
||||
<p>
|
||||
einem solchen Kontext könnte man dann einen Marker-Typ erkennen und an
|
||||
die tatsächliche Instanz binden.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<u>&#55357;&#56481; Und in der Tat</u>: diesen Kontext g&#228;be es in der
|
||||
</p>
|
||||
<p>
|
||||
<u>�� Und in der Tat</u>: diesen Kontext gäbe es in der
|
||||
Hilfsfunktion buildLauncher()
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#3551b4" DESTINATION="ID_1017963709" ENDARROW="Default" ENDINCLINATION="8;-31;" ID="Arrow_ID_855336150" STARTARROW="None" STARTINCLINATION="-132;6;"/>
|
||||
<icon BUILTIN="forward"/>
|
||||
<node CREATED="1696978822594" ID="ID_1410342065" MODIFIED="1696979058894" TEXT="diese Lösung wäre zuverlässig, sicher und effizient">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<ul>
|
||||
<li>
|
||||
|
|
@ -65438,13 +65427,12 @@
|
|||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1696978865091" ID="ID_1134916435" MODIFIED="1696978893087" TEXT="aber schön ist sie nicht — bestenfalls gut versteckt"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696979065849" ID="ID_1017963709" MODIFIED="1697023014065" TEXT="Umsetzung versuchen">
|
||||
<node COLOR="#435e98" CREATED="1696979065849" ID="ID_1017963709" MODIFIED="1697050405966" TEXT="Umsetzung versuchen">
|
||||
<linktarget COLOR="#3551b4" DESTINATION="ID_1017963709" ENDARROW="Default" ENDINCLINATION="8;-31;" ID="Arrow_ID_855336150" SOURCE="ID_1356286451" STARTARROW="None" STARTINCLINATION="-132;6;"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1697022864978" ID="ID_360386085" MODIFIED="1697022989269" TEXT="im Prinzip „ganz einfach“">
|
||||
|
|
@ -65457,6 +65445,33 @@
|
|||
<icon BUILTIN="smiley-angry"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1697050416768" ID="ID_1615729676" MODIFIED="1697050582236" TEXT="die Hilfsfunktion ...">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1697050430395" ID="ID_1669320853" MODIFIED="1697050438782" TEXT="extrahieren ⟶ lib/function.hpp">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1697050439986" ID="ID_1328885131" MODIFIED="1697050554033" TEXT="könnte einfacher und generisher sein">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Es gibt keinen Grund, die Ersetzung nur an 2.Stelle im Tupel zu machen; auch ist es nicht notwendig, die Typen irgendwie festzunageln. Allein die Gegenwart des Marker-Typs genügt, denn diesen setzt man nur explizit ein. Damit wäre diese Funktion auch auf reine Argument-Tupel anwendbar, nicht nur (wie hier) auf Invocation-Tupel (functor, args...)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1697050554898" ID="ID_1031448830" MODIFIED="1697050570497" TEXT="sollte jedwede Kopie vermeiden">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1697050571552" ID="ID_333850507" MODIFIED="1697050580451" TEXT="...und gehört im Test abgedeckt">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1697050588182" ID="ID_1656504822" MODIFIED="1697050631074" TEXT="Problem damit gelöst">
|
||||
<arrowlink COLOR="#07a068" DESTINATION="ID_1379899935" ENDARROW="Default" ENDINCLINATION="479;18;" ID="Arrow_ID_645882664" STARTARROW="None" STARTINCLINATION="268;31;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -65877,44 +65892,35 @@
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696972878105" ID="ID_880873658" MODIFIED="1696972924189">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
allerdings: abgeleitete Klassen <b>leben gefährlich</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1696972938795" ID="ID_1194001800" MODIFIED="1696972960949" TEXT="wenn im Konstruktor etwas schiefgeht"/>
|
||||
<node CREATED="1696972967768" ID="ID_1795585703" MODIFIED="1696972989481" TEXT="dann gelingt nicht einmal die Heap-Allokation vollständig"/>
|
||||
<node CREATED="1696973111469" ID="ID_229806295" MODIFIED="1696973186990" TEXT="und der Destruktor blockt und scheitert nicht...">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Ein normaler Thread (und ein Joinable) würden den Aufruf des Destruktors verbieten, und damit die Applikation terminieren
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1696972994851" ID="ID_983723928" MODIFIED="1696973016584">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
aber der Thread <i>ist schon „unterwegs“</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1696973047334" ID="ID_1485957927" MODIFIED="1696973196674" TEXT="Mitigation: nicht in die Thread-Funktion eintreten wenn nicht isAlive()">
|
||||
|
|
@ -65923,16 +65929,13 @@
|
|||
<node CREATED="1696973227990" ID="ID_481018550" MODIFIED="1696976336073" TEXT="aber wenn jemand explizit detach() macht..."/>
|
||||
<node CREATED="1696973241644" ID="ID_1093970050" MODIFIED="1696973309225" TEXT="eigentlich müßte man diesen Fall auf einen »Autonomous Thread« einschränken">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...aber das gibt mein Framework nicht her
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -66301,14 +66304,22 @@
|
|||
</node>
|
||||
</node>
|
||||
<node CREATED="1696538743210" ID="ID_1370366397" MODIFIED="1696538750437" TEXT="Tests ergänzen">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696538756712" ID="ID_1688404846" MODIFIED="1696541608160" TEXT="ThreadWrapperAutonomous_test">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1696538756712" ID="ID_1688404846" MODIFIED="1697050726434" TEXT="ThreadWrapperAutonomous_test">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1696539571988" ID="ID_791561993" MODIFIED="1696966349054" TEXT="demonstriert: einen Thread komplett abgekoppelt starten">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696966318864" ID="ID_1955344707" MODIFIED="1696966351181" TEXT="sauberes Memory-Management belegen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1696966318864" ID="ID_1955344707" MODIFIED="1697050723749" TEXT="sauberes Memory-Management belegen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1696971867646" ID="ID_1915512401" MODIFIED="1696971888573" TEXT="lib/test/testdummy.hpp �� als Member verwenden"/>
|
||||
<node COLOR="#435e98" CREATED="1697050651493" ID="ID_92765841" MODIFIED="1697050712336" TEXT="AUA: das mit der member-Funktion geht ja gar nicht">
|
||||
<arrowlink COLOR="#5d6faa" DESTINATION="ID_57182560" ENDARROW="Default" ENDINCLINATION="-230;791;" ID="Arrow_ID_1090153547" STARTARROW="None" STARTINCLINATION="772;-34;"/>
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1697050598820" ID="ID_1379899935" MODIFIED="1697050718681" TEXT="Demonstration: kann in der Tat auch eine Member-Funktion aufrufen">
|
||||
<linktarget COLOR="#07a068" DESTINATION="ID_1379899935" ENDARROW="Default" ENDINCLINATION="479;18;" ID="Arrow_ID_645882664" SOURCE="ID_1656504822" STARTARROW="None" STARTINCLINATION="268;31;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696538825003" ID="ID_1787030725" MODIFIED="1696539451332" TEXT="ThreadWrapperLifecycle_test">
|
||||
|
|
|
|||
Loading…
Reference in a new issue