BufferProvider: consider how to setup and wire the LocalMemPool
Basically the setup should be symmetrical to the `BufferStage` setup, which implies to install the `LocalMemPool` as a thread-local »slice«. However, in addition we need a mechanism to trigger an automatic clean-up of the local pool whenever a worker-thread terminates, with the additional complication that thread-local variables are effectively static. Since `LocalMemPool` is written such as to abstract from the setup environment, we need to inject a shutdown function from the setup within `LocalSlice`, thereby directly accessing the `EngineBufferManager` via dependency-injection.
This commit is contained in:
parent
c4db787b25
commit
0204438147
3 changed files with 158 additions and 16 deletions
|
|
@ -42,6 +42,31 @@ namespace mem {
|
|||
class LocalBufferStore
|
||||
: public BufferProviderSetup::Store
|
||||
{
|
||||
struct SetupPool;
|
||||
using LocalPool = lib::LocalSlice<LocalMemPool, SetupPool>;
|
||||
using GlobalPool = lib::Depend<EngineBufferManager>;
|
||||
|
||||
struct SetupPool
|
||||
{
|
||||
using Service = LocalMemPool;
|
||||
|
||||
static LocalMemPool
|
||||
init()
|
||||
{
|
||||
return LocalMemPool{[](LocalMemPool& pool2close)
|
||||
{
|
||||
pool2close.purge([](Buff* mem, size_t siz)
|
||||
{
|
||||
Alloc alloc{mem,siz};
|
||||
GlobalPool globalPool;
|
||||
globalPool().supply(alloc);
|
||||
});
|
||||
}};
|
||||
}
|
||||
};
|
||||
|
||||
LocalPool localReg_;
|
||||
GlobalPool globalReg_;
|
||||
|
||||
public:
|
||||
LocalBufferStore()
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@
|
|||
#include "vault/mem/engine-buffer-manager.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
|
|
@ -98,6 +99,7 @@ namespace mem {
|
|||
|
||||
using std::move;
|
||||
using std::forward;
|
||||
using std::invocable;
|
||||
using util::unConst;
|
||||
using util::isLimited;
|
||||
|
||||
|
|
@ -123,7 +125,8 @@ namespace mem {
|
|||
*/
|
||||
class LocalMemPool
|
||||
: public AllocReceiver
|
||||
{
|
||||
{ // NonCopyable
|
||||
|
||||
struct Block
|
||||
{
|
||||
Alloc alloc{nullptr,0};
|
||||
|
|
@ -143,11 +146,29 @@ namespace mem {
|
|||
|
||||
int32_t maxScore_{1};
|
||||
|
||||
std::function<void(LocalMemPool&)> shutdownHook_{};
|
||||
|
||||
public:
|
||||
LocalMemPool()
|
||||
: AllocReceiver{}
|
||||
, blocks_{}
|
||||
{ }
|
||||
// NonCopyable
|
||||
|
||||
template<invocable<LocalMemPool&> FUN>
|
||||
explicit
|
||||
LocalMemPool (FUN&& onShutdown)
|
||||
: AllocReceiver{}
|
||||
, blocks_{}
|
||||
, shutdownHook_{forward<FUN> (onShutdown)}
|
||||
{ }
|
||||
|
||||
~LocalMemPool()
|
||||
{
|
||||
if (shutdownHook_)
|
||||
shutdownHook_(*this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ===== Pool Access API ===== */
|
||||
|
|
@ -283,7 +304,7 @@ namespace mem {
|
|||
* @param siz precise size of the memory block(s) to yield
|
||||
* @return actual number of allocations removed from the pool.
|
||||
*/
|
||||
template<class FUN> ////////TODO requires std::invocable<FUN,Buff*,size_t>
|
||||
template<invocable<Buff*,size_t> FUN>
|
||||
uint
|
||||
yield (uint cnt, size_t siz, FUN&& consumer)
|
||||
{
|
||||
|
|
@ -317,7 +338,7 @@ namespace mem {
|
|||
* \a degree ≡ 0.5 retains all matches that were frequently successful.
|
||||
* @return actual number of allocations removed from the pool.
|
||||
*/
|
||||
template<class FUN> ////////TODO requires std::invocable<FUN,Buff*,size_t>
|
||||
template<invocable<Buff*,size_t> FUN>
|
||||
uint
|
||||
cleanup (double degree, FUN&& consumer)
|
||||
{
|
||||
|
|
@ -345,6 +366,23 @@ namespace mem {
|
|||
return removed;
|
||||
}
|
||||
|
||||
/** unconditionally dispose of the pool's entire contents.
|
||||
* @warning there must not be any allocations in use when invoking this function
|
||||
*/
|
||||
template<invocable<Buff*,size_t> FUN>
|
||||
uint
|
||||
purge (FUN&& consumer)
|
||||
{
|
||||
ingest();
|
||||
///////////////////////////////////////OOO need a way to »lock down« the inqueue at that point
|
||||
for (Block& block : blocks_)
|
||||
{
|
||||
REQUIRE (not block.used);
|
||||
consumer (block.alloc.mem, block.alloc.siz);
|
||||
blocks_.clear();
|
||||
}
|
||||
ENSURE (this->empty());
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
|
|
|
|||
|
|
@ -144403,7 +144403,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1776292987880" ID="ID_808037956" MODIFIED="1776477504910" TEXT="Zugriff über Pointer-artige Syntax">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1776293021744" FOLDED="true" ID="ID_808171568" MODIFIED="1776717333143" TEXT="Problem: thread_local ist implizit statisch">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1776293021744" FOLDED="true" ID="ID_808171568" MODIFIED="1779131275381" TEXT="Problem: thread_local ist implizit statisch">
|
||||
<linktarget COLOR="#a61032" DESTINATION="ID_808171568" ENDARROW="Default" ENDINCLINATION="11;-94;" ID="Arrow_ID_66477268" SOURCE="ID_290625266" STARTARROW="None" STARTINCLINATION="257;14;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1776293040334" ID="ID_555811092" MODIFIED="1776293060463" TEXT="das heißt es ist eine »versteckte globale Variable«"/>
|
||||
|
|
@ -144413,6 +144413,9 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node CREATED="1776436869043" ID="ID_1444097357" MODIFIED="1776439761005" TEXT="aber — Buffer-Metadata baucht eine RootID">
|
||||
<arrowlink COLOR="#5b39d7" DESTINATION="ID_1105234662" ENDARROW="Default" ENDINCLINATION="113;-353;" ID="Arrow_ID_8614584" STARTARROW="None" STARTINCLINATION="-450;30;"/>
|
||||
</node>
|
||||
<node CREATED="1779131181376" ID="ID_1507803308" MODIFIED="1779131272555" TEXT="aber — ein »Local Pool« muß am Thread-Ende aufgeräumt werden">
|
||||
<arrowlink COLOR="#8233d1" DESTINATION="ID_1569602452" ENDARROW="Default" ENDINCLINATION="-746;-38;" ID="Arrow_ID_1519809069" STARTARROW="None" STARTINCLINATION="-695;30;"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1776437522354" ID="ID_1884586370" MODIFIED="1776437530564" TEXT="Bedeutung für den Lebenszyklus">
|
||||
<node CREATED="1776437601915" ID="ID_813699540" MODIFIED="1776437622336" TEXT="wäre künstlich"/>
|
||||
|
|
@ -144995,6 +144998,72 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1778979188506" ID="ID_1435066016" MODIFIED="1778979206192" TEXT="Zugriff auf Thread-Local Mem-Pool und EngineBufferManager">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1779128982798" ID="ID_1913652442" MODIFIED="1779128995471" TEXT="Problem Clean-up">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1779128999922" ID="ID_1435970090" MODIFIED="1779129012818" TEXT="dieser wird vom thread-local Subobjekt getriggert"/>
|
||||
<node CREATED="1779129014668" ID="ID_978040113" MODIFIED="1779129075918" TEXT="der LocalBufferStore bekommt das nicht einmal mit">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
<body>
|
||||
<p>
|
||||
...weil es ja durch das Ende eines Thread verursacht wird, wodurch ein thread-local Subobjekt out of scope geht.
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1779129078429" ID="ID_1921726698" MODIFIED="1779129106317" TEXT="aber die Service-Verbindungen sind nur im LocalBuffer gegeben"/>
|
||||
<node CREATED="1779130807327" ID="ID_1569602452" MODIFIED="1779131264472" TEXT="⟹ also wird ein shutdown-Hook notwendig">
|
||||
<linktarget COLOR="#8233d1" DESTINATION="ID_1569602452" ENDARROW="Default" ENDINCLINATION="-746;-38;" ID="Arrow_ID_1519809069" SOURCE="ID_1507803308" STARTARROW="None" STARTINCLINATION="-695;30;"/>
|
||||
<node CREATED="1779130847250" ID="ID_222831030" MODIFIED="1779135184435" TEXT="das ganze Thema kommt mir bekannt vor...">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
<body>
|
||||
<p>
|
||||
...ich hatte bereits über die Konfiguration nachgedacht, und dann für LocalSlice ein policy-based-design verwendet, allerdings in einer Form so daß es weiterhin default-constructible bleibt. Leider kann ich hier den Shutdown / clean-Up <i>nicht einfach anbauen,</i> da LocalSlice davon garnichts merkt.
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1779130986850" ID="ID_1806655906" MODIFIED="1779131349575" TEXT="erneut stellt sich das Problem der effektiv-statischen Instanz">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1779131365999" ID="ID_660464086" MODIFIED="1779131414390">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
<body>
|
||||
<p>
|
||||
eine Verdrahtung auf das <i>managing Object</i> ist nur indirekt (trickreich) möglich
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1779133795132" ID="ID_1232765189" MODIFIED="1779133813258" TEXT="aber glücklicherweise brauchen wir tatsächlich nur den Zugriff auf EngineBufferManager"/>
|
||||
<node CREATED="1779133821370" ID="ID_627116251" MODIFIED="1779134164150" TEXT="das wäre zwar etwas indirekt, aber akzeptabel, da es in einem lokalen Setup stattfindet">
|
||||
<icon BUILTIN="closed"/>
|
||||
</node>
|
||||
<node CREATED="1779135986170" ID="ID_1418977742" MODIFIED="1779136269411" TEXT="und es wird hässlich, wenngleich auch nicht Performance-relevant">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
<body>
|
||||
<p>
|
||||
...denn ich muß irgendwie einen clean-up-Hook in jede Instanz installieren, sofern ich LocalMemPool weiterhin von der sonstigen Implementierung entkoppelt haben möchte. Das bedingt dann entweder, einen Template-Parameter einzuführen, oder std::function mit einer Konstruktor-Variante. Letzteres erscheint attraktiv, da es diesen Sachverhalt etwas »unter den Teppich kehrt« und eigentlich erst auffällt, wenn man das PROD-Setup für die Engine sieht...
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="smily_bad"/>
|
||||
<node CREATED="1779140476970" ID="ID_1853141177" MODIFIED="1779140488380" TEXT="führe also eine shutdown-function ein"/>
|
||||
<node CREATED="1779140489560" ID="ID_1942203871" MODIFIED="1779140502858" TEXT="verwende die Config von LocalSlice um die zu injizieren"/>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1779140507822" ID="ID_1541520016" MODIFIED="1779140836908" TEXT="weitere Komplikation: Race im Shutdown">
|
||||
<arrowlink COLOR="#e5024c" DESTINATION="ID_241014081" ENDARROW="Default" ENDINCLINATION="-1049;0;" ID="Arrow_ID_1884336660" STARTARROW="None" STARTINCLINATION="-946;65;"/>
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1779140860563" ID="ID_187364117" MODIFIED="1779140879122" TEXT="das zeigt: ein explizitesr Schutzmechanismus ist notwendig"/>
|
||||
<node CREATED="1779140879780" ID="ID_418804808" MODIFIED="1779140902765" TEXT="dieser muß bereits in der Basisklasse AllocReceiver sitzen"/>
|
||||
<node CREATED="1779140904161" ID="ID_292316056" MODIFIED="1779140919843" TEXT="der darf auf keinerlei dynamischen Speicher zugreifen"/>
|
||||
<node CREATED="1779140953120" ID="ID_475594715" MODIFIED="1779140969596" TEXT="die Objekt-Identität muß aus der Speicheradresse gewonnen werden"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1778802491003" ID="ID_1880673250" MODIFIED="1778979225756" TEXT="brauche noch einen Trigger-Mechanismus für das heuristische Clean-up">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1778805833301" ID="ID_493965127" MODIFIED="1778806330596" TEXT="man könnte nach jeder de-Allokation einen partiellen clean-up machen">
|
||||
|
|
@ -145026,8 +145095,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
Es müßt nach jeder de-Allokation die ganze Blockliste gescannt werden, wobei erwartungsgemäß nach den meisten Scans nichts zur Freigabe gefunden wird
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1778806342604" ID="ID_447948169" MODIFIED="1778806371642" TEXT="man könnte stattdessen das Prüf-Intervall vergrößern">
|
||||
|
|
@ -145769,8 +145837,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
<node CREATED="1776814507533" ID="ID_189865287" MODIFIED="1776814576271" TEXT="Ownership / Transaktionelle Sicherheit">
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1776816810560" ID="ID_1402352728" MODIFIED="1778205114333" TEXT="das System muß auch korrekt arbeiten, wenn ein Worker-Thread terminiert">
|
||||
<arrowlink COLOR="#e01436" DESTINATION="ID_609664480" ENDARROW="Default" ENDINCLINATION="-1139;0;" ID="Arrow_ID_649333039" STARTARROW="None" STARTINCLINATION="707;0;"/>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1776816810560" ID="ID_1402352728" MODIFIED="1779140437311" TEXT="das System muß auch korrekt arbeiten, wenn ein Worker-Thread terminiert">
|
||||
<arrowlink COLOR="#e01436" DESTINATION="ID_609664480" ENDARROW="None" ENDINCLINATION="-1139;0;" ID="Arrow_ID_649333039" STARTARROW="Default" STARTINCLINATION="707;0;"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1776816880663" ID="ID_233138855" MODIFIED="1776816975061" TEXT="das ist nicht-trivial — ohne weitere Maßnamen »verlieren« wir Buffer">
|
||||
|
|
@ -146843,8 +146911,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1778205040426" ID="ID_609664480" MODIFIED="1778205118401" TEXT="weiteres Problem: Race mit Ende des Worker-Thread">
|
||||
<linktarget COLOR="#e01436" DESTINATION="ID_609664480" ENDARROW="Default" ENDINCLINATION="-1139;0;" ID="Arrow_ID_649333039" SOURCE="ID_1402352728" STARTARROW="None" STARTINCLINATION="707;0;"/>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1778205040426" ID="ID_609664480" MODIFIED="1779140437311" TEXT="weiteres Problem: Race mit Ende des Worker-Thread">
|
||||
<linktarget COLOR="#e01436" DESTINATION="ID_609664480" ENDARROW="None" ENDINCLINATION="-1139;0;" ID="Arrow_ID_649333039" SOURCE="ID_1402352728" STARTARROW="Default" STARTINCLINATION="707;0;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1778205127309" ID="ID_174843767" MODIFIED="1778205132800" TEXT="Beispiel-Szenario">
|
||||
<node CREATED="1778205135600" ID="ID_1730604347" MODIFIED="1778205230908" TEXT="neuer Job ⟹ Anforderung an EngineBufferManager">
|
||||
|
|
@ -146902,7 +146970,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1778372507757" ID="ID_228507573" MODIFIED="1778372578208" TEXT="eine Möglichkeit wäre, eine zusätzliche Sicherung im empfangenden Code vorzusehen">
|
||||
<node CREATED="1778372507757" ID="ID_228507573" MODIFIED="1779140798964" TEXT="eine Möglichkeit wäre, eine zusätzliche Sicherung im empfangenden Code vorzusehen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
|
|
@ -146911,6 +146979,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#2b53d4" DESTINATION="ID_255577978" ENDARROW="Default" ENDINCLINATION="443;20;" ID="Arrow_ID_57636127" STARTARROW="None" STARTINCLINATION="320;11;"/>
|
||||
</node>
|
||||
<node CREATED="1778372538869" ID="ID_398624236" MODIFIED="1778373145721" TEXT="diese Sicherung müßte allerdings wirksam werden vor dem ersten tatsächlichen Speicherzugriff">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -146944,6 +147013,18 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1779140529611" ID="ID_241014081" MODIFIED="1779140636770" TEXT="ein weiterer ähnlicher Race besteht im Destruktor + shotdown-Hook">
|
||||
<linktarget COLOR="#e5024c" DESTINATION="ID_241014081" ENDARROW="Default" ENDINCLINATION="-1049;0;" ID="Arrow_ID_1884336660" SOURCE="ID_1541520016" STARTARROW="None" STARTINCLINATION="-946;65;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1779140649391" ID="ID_1221279387" MODIFIED="1779140665105" TEXT="ein anderer Thread könnte grade mit der Zustellung anfangen"/>
|
||||
<node CREATED="1779140665976" ID="ID_694831112" MODIFIED="1779140680958" TEXT="...während der LocalMemPool seinen Destruktor bearbeitet"/>
|
||||
<node CREATED="1779140681992" ID="ID_1268043667" MODIFIED="1779140711019" TEXT="also leider noch nicht tot ist ��">
|
||||
<icon BUILTIN="smiley-oh"/>
|
||||
</node>
|
||||
<node CREATED="1779140722186" ID="ID_255577978" MODIFIED="1779140798964" TEXT="⟹ das Sicherheits-Feature muß also sogar explizit triggerbar sein">
|
||||
<linktarget COLOR="#2b53d4" DESTINATION="ID_255577978" ENDARROW="Default" ENDINCLINATION="443;20;" ID="Arrow_ID_57636127" SOURCE="ID_228507573" STARTARROW="None" STARTINCLINATION="320;11;"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1778118843392" ID="ID_45310528" MODIFIED="1778118856450" TEXT="Eingang ≙ zurückgegebene Allokationen">
|
||||
<node CREATED="1778118860685" ID="ID_744369649" MODIFIED="1778118884334" TEXT="hier kommt eine Alloc, d.h. (Buffer-Adr, Size)"/>
|
||||
|
|
@ -147176,8 +147257,8 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
</body>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#e7f3c5" DESTINATION="ID_1339362365" ENDARROW="Default" ENDINCLINATION="273;14;" ID="Arrow_ID_74341588" STARTARROW="None" STARTINCLINATION="226;-11;"/>
|
||||
<linktarget COLOR="#cffd68" DESTINATION="ID_1723782536" ENDARROW="Default" ENDINCLINATION="2031;68;" ID="Arrow_ID_1674470149" SOURCE="ID_226540112" STARTARROW="None" STARTINCLINATION="1004;42;"/>
|
||||
<linktarget COLOR="#c9e1fe" DESTINATION="ID_1723782536" ENDARROW="Default" ENDINCLINATION="-2385;0;" ID="Arrow_ID_1515784613" SOURCE="ID_575451700" STARTARROW="None" STARTINCLINATION="1597;63;"/>
|
||||
<linktarget COLOR="#cffd68" DESTINATION="ID_1723782536" ENDARROW="Default" ENDINCLINATION="2031;68;" ID="Arrow_ID_1674470149" SOURCE="ID_226540112" STARTARROW="None" STARTINCLINATION="1004;42;"/>
|
||||
<icon BUILTIN="forward"/>
|
||||
</node>
|
||||
<node CREATED="1778508357967" ID="ID_1467114460" MODIFIED="1778508767506" TEXT="naheliegende Lösung: Hintergrundthread">
|
||||
|
|
@ -147419,8 +147500,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
...und das geht nicht mit dem fill()-Populator, denn dieser materialisiert alle Argumente als Kopien. Man könnte das ändern, müßte dann aber explizit ein perfect-forwarding-Tupel bauen. Das war mir jetzt alles zu mühsam
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#b6020c" CREATED="1778788232367" ID="ID_134775139" MODIFIED="1778788330594" TEXT="manchmal ist es essentiell, für jeden Thread ein separates Lambda zu konstruieren">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
|
|
@ -147430,8 +147510,7 @@ StM_bind(Builder<R1> b1, Extension<R1,R2> extension)
|
|||
das ist im Besonderen relevant, wenn die captures nicht-triviale Operationen in der Initialisierung verwenden. Da der fill()-Popoulator kopiert, würden sich alle Threads das gleiche Lambda teilen, und daher auf den gleichen Werten arbeiten. Das ist <b>eine subtile Falle</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="clanbomber"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue