/
Ant010ff
/
ffpp
Обзор
Документация
Войти
/
Ant010ff
/
ffpp
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
test/chains/main.cpp
817 строк
30 KB
Ant010ff
Demo code update; exception-related refactoring (FFPP_TRY / FFPP_CATCH).
13 июн 2026, 15:39
13 июн 2026, 15:39
d23feb5
Код
Авторство
О чём код?
#include "../common/common.hpp" //Declaring broker policy with wstring identifiers in current test (just for demo purposes). struct Policy : CommonPolicy { struct ResourcePolicy : ffpp::DefaultResourcePolicy { struct IdProvider { using Id = std::wstring; using Hash = std::hash<Id>; static constexpr Id InvalidId() { return { }; } static Id GenerateId() { //Return string representation of default 64-bit integer identifier. #if !(defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE <= 12)) return std::format(L"{{{:#018X}}}", ffpp::IdProvider::GenerateId()); #else std::wstringstream wss; wss << L"0x" << std::setw(16) << std::uppercase << std::setfill(L'0') << std::hex << ffpp::IdProvider::GenerateId(); return wss.str(); #endif } }; using IdProviderT = IdProvider; }; using ResourcePolicyT = ResourcePolicy; using IdProviderT = ResourcePolicyT::IdProviderT; using Id = IdProviderT::Id; }; using BrokerT = ffpp::FunctionalBroker<Policy>; using ActorT = ffpp::FunctionalActor<true, Policy>; ////Utils///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void AsyncRandomString(BrokerT::Id idRequest, bool bSimulateLatency = true) { AsyncRandomString<BrokerT, ActorT>(idRequest, bSimulateLatency); } void AsyncRandomStringVector(BrokerT::Id idRequest, std::vector<std::string> const& vStrings, bool bSimulateLatency = true) { AsyncRandomStringVector<BrokerT, ActorT>(idRequest, vStrings, bSimulateLatency); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestSimpleChain() { auto [_, sgComplete] = ffpp::BeginJoin(); Accent::Put("Simulating simple async chain..."); BrokerT::Chain() .Chain([] (auto idChain) { SimulateLatency(idChain, "stage 1"); }) .Chain([] (auto idChain) { SimulateLatency(idChain, "stage 2"); }) .Chain([sgComplete = std::move(sgComplete)] (auto idChain) { SimulateLatency(idChain, "stage 3, completed"); }) //.Complete() //Chain will be finalized and removed from broker. This not necessary, see ffpp::FunctionalBroker::Chain. ; Info::Put("Waiting for chain..."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestChainCache() { auto [_, sgComplete] = ffpp::BeginJoin(); Accent::Put("Testing async chain cache..."); BrokerT::Chain<ffpp::Flags::Keep>() //reusable chain .Chain([] (auto idChain) { SimulateLatency(idChain, "stage 1"); }) .Chain([] (auto idChain) { SimulateLatency(idChain, "stage 2"); }) .Chain([sgComplete = std::move(sgComplete), nRepeat = 10] (auto idChain) mutable { SimulateLatency(idChain, "stage 3"); if(--nRepeat > 0) { //Acquire and submit chain. Info::Put("Looping chain..."); BrokerT::Chain(idChain); } else { Info::Put("Finalizing chain..."); BrokerT::Finalize(idChain); } }) .Fence() //incomplete (reusable) chain's stop point ; Info::Put("Waiting for chain..."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestFencedChain() { auto [_, sgComplete] = ffpp::BeginJoin(); Accent::Put("Testing fenced chain..."); BrokerT::Chain<ffpp::Flags::Keep>() //reusable chain .Chain([sgComplete = std::move(sgComplete)] (auto idChain) { Info::Put("Stage 1..."); /*if()*/ BrokerT::Chain(idChain).Forward(); }) .Fence() //Forward stage will be invoked if previous one called Forward() on chain object. .Chain([] (auto idChain) { Info::Put("Stage 2..."); /*if()*/ BrokerT::Chain(idChain).Forward(); /*else if() BrokerT::Chain(idChain).Continue();*/ }) .Fence() .Chain([nRepeat = 10] (auto idChain) mutable { Info::Put("Stage 3..."); if(--nRepeat > 0) { Info::Put("Looping chain..."); BrokerT::Chain(idChain); } else { Info::Put("Finalizing chain..."); BrokerT::Finalize(idChain); } }) .Fence() ; Info::Put("Waiting for chain..."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestContinuingChain() { auto [_, sgComplete] = ffpp::BeginJoin(); Accent::Put("Testing continuing chain..."); BrokerT::Chain<ffpp::Flags::Keep>() //reusable chain .Chain([sgComplete = std::move(sgComplete)] (auto idChain) { Info::Put("Stage 1..."); }) .Chain([mtDevice = std::mt19937((std::random_device())())] (auto idChain) mutable { Info::Put("Stage 2..."); //Randomly restarting chain... if(mtDevice() % 100 > 50) { Info::Put("Restarting chain..."); //Restarts chain (much like a loop's 'continue' operator) from the next Fence point. BrokerT::Chain(idChain).Continue(); } //else BrokerT::Chain(idChain).Forward(); //see Fence [1] }) .Fence(true) //[1] .Chain([nRepeat = 10] (auto idChain) mutable { Info::Put("Stage 3..."); if(--nRepeat > 0) { Info::Put("Looping chain..."); BrokerT::Chain(idChain); } else { Info::Put("Finalizing chain..."); BrokerT::Finalize(idChain); } }) .Fence() ; Info::Put("Waiting for chain..."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestRequestChain() { auto [_, sgComplete] = ffpp::BeginJoin(); Accent::Put("Simulating async request chain..."); BrokerT::Chain() .Request<std::string>( [] (BrokerT::Id idRequest) { AsyncRandomString(idRequest); }, [] (std::string const& strResponse, BrokerT::Id /*idChain*/) { Info::Put("Request completed with response:", strResponse); return strResponse; } ) .Request<std::vector<std::string>>( [] (std::string const& strResponse, BrokerT::Id idRequest) { AsyncRandomStringVector(idRequest, { strResponse }); }, [] (std::vector<std::string> const& vResponse, BrokerT::Id /*idChain*/) { return VectorToString(vResponse); } ) .Chain([sgComplete = std::move(sgComplete)] (std::string const& strStrings, BrokerT::Id /*idChain*/) { Info::Put("Chain completed with result:", strStrings); }) ; Info::Put("Waiting for response..."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// auto RequestChainStage1() { return BrokerT::Chain() .Request<std::string>( [] (BrokerT::Id idRequest) { AsyncRandomString(idRequest); }, [] (std::string const& strResponse, BrokerT::Id /*idChain*/) { Info::Put("Requested std::string (1):", strResponse); return strResponse; } ) .Request<std::vector<std::string>>( [] (std::string const& strResponse, BrokerT::Id idRequest) { AsyncRandomStringVector(idRequest, { strResponse }); }, [] (std::vector<std::string> const& vResponse, BrokerT::Id /*idChain*/) { Info::Put("Requested vector (2):", VectorToString(vResponse)); return vResponse; } ) ; } auto RequestChainStage2(auto&& aChainer) { return aChainer .template Request<std::vector<std::string>>( [] (std::vector<std::string> const& vStrings, BrokerT::Id idRequest) { AsyncRandomStringVector(idRequest, vStrings); }, [] (std::vector<std::string> const& vResponse, BrokerT::Id /*idChain*/) { Info::Put("Requested vector (3):", VectorToString(vResponse)); return vResponse; } ) .template Request<std::vector<std::string>>( [] (std::vector<std::string> const& vStrings, BrokerT::Id idRequest) { AsyncRandomStringVector(idRequest, vStrings); }, [] (std::vector<std::string> const& vResponse, BrokerT::Id /*idChain*/) { auto const strResult = VectorToString(vResponse); Info::Put("Result vector of strings (4):", strResult); return strResult; } ) ; } void TestRequestStagedChain() { auto [_, sgComplete] = ffpp::BeginJoin(); Accent::Put("Simulating async request multistage chain..."); auto aChainer = RequestChainStage1(); RequestChainStage2(aChainer) .Chain([sgComplete = std::move(sgComplete)] (std::string const& strStrings, BrokerT::Id /*idChain*/) { Info::Put("Multistage chain completed with:", strStrings); }) ; Info::Put("Waiting for response..."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestReceiveChain() { auto [_, sgComplete] = ffpp::BeginJoin(); Accent::Put("Simulating async receive chain..."); BrokerT::Id const c_idReceive1 { L"TestReceiveChain.Receive1" }, c_idReceive2 { L"TestReceiveChain.Receive2" } ; BrokerT::Chain() .Receive<std::string>(c_idReceive1, [] (std::string const& strResponse, BrokerT::Id /*idChain*/) { Info::Put("Received first:", strResponse); return "Receive1:" + strResponse; }) .Receive<std::string>(c_idReceive2, [] (std::string const& strResponse, std::string const& strReceive1, BrokerT::Id /*idChain*/) { Info::Put("Received second:", strResponse); return std::vector<std::string> { strReceive1, "Receive2:" + strResponse }; }) .Chain([sgComplete = std::move(sgComplete)] (std::vector<std::string> const& vResult, BrokerT::Id /*idChain*/) { Info::Put("Receive chain completed with:", VectorToString(vResult)); }) ; AsyncRandomString(c_idReceive2); AsyncRandomString(c_idReceive1); Info::Put("Waiting for response..."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestRequestReceiveChain() { auto [_, sgComplete] = ffpp::BeginJoin(); Accent::Put("Simulating async request-receive chain..."); BrokerT::Id const c_idReceive { L"TestRequestReceiveChain.Receive" }; BrokerT::Chain() .Request<std::string>( [] (BrokerT::Id idRequest) { AsyncRandomString(idRequest); }, [] (std::string const& strResponse, BrokerT::Id /*idChain*/) { Info::Put("Requested string:", strResponse); return "Request:" + strResponse; } ) .Receive<std::string>(c_idReceive, [] (std::string const& strResponse, std::string const& strRequested, BrokerT::Id /*idChain*/) { Info::Put("Received string:", strResponse); return std::vector<std::string> { strRequested, "Receive:" + strResponse }; }) .Chain([sgComplete = std::move(sgComplete)] (std::vector<std::string> const& vResult, BrokerT::Id /*idChain*/) { Info::Put("Request-receive chain completed with:", VectorToString(vResult)); }) ; AsyncRandomString(c_idReceive); Info::Put("Waiting for response..."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestReceiveRequestChain() { auto [_, sgComplete] = ffpp::BeginJoin(); Accent::Put("Simulating async receive-request chain..."); BrokerT::Id const c_idReceive { L"TestReceiveRequestChain.Receive" }; BrokerT::Chain() .Chain([sgComplete = std::move(sgComplete)] (BrokerT::Id /*idChain*/) { Info::Put("Starting receive-request chain..."); }) .Receive<std::string>(c_idReceive, [] (std::string const& strResponse, BrokerT::Id /*idChain*/) { Info::Put("Received string:", strResponse); return "Receive:" + strResponse; }) .Request<std::string>( [] (std::string const& strReceived, BrokerT::Id idRequest) { AsyncRandomString(idRequest); return strReceived; }, [] (std::string const& strResponse, std::string const& strReceived, BrokerT::Id /*idChain*/) { Info::Put("Requested string:", strResponse); return std::vector<std::string> { strReceived, "Request:" + strResponse }; } ) .Chain([sgComplete = std::move(sgComplete)] (std::vector<std::string> const& vResult, BrokerT::Id /*idChain*/) { Info::Put("Receive-request chain completed with:", VectorToString(vResult)); }) ; AsyncRandomString(c_idReceive); Info::Put("Waiting for response..."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestRequestReceiveJointChains() { using namespace std::literals; auto [_, sgComplete] = ffpp::BeginJoin(); Accent::Put("Simulating async request-receive joint chains..."); BrokerT::Id const c_idGroup { L"TestRequestReceiveJointChains.Group" } , c_idReceive1 { L"TestRequestReceiveJointChains.Receive1" } , c_idReceive2 { L"TestRequestReceiveJointChains.Receive2" } , c_idChain1 { L"TestRequestReceiveJointChains.Chain1" } , c_idChain2 { L"TestRequestReceiveJointChains.Chain2" } , c_idChain3 { L"TestRequestReceiveJointChains.Chain3" } ; //Chain (3) BrokerT::Chain(c_idChain3, c_idGroup) //incomplete (reusable) chain .Junction<std::string>(c_idChain3, [sgComplete] (std::string const& strSecond, BrokerT::Id idChain) { Info::Put("Chain (3) [", idChain, "] received chain (2) result:", strSecond); return std::tuple { strSecond, sgComplete }; }) .Request<std::string>( [] (std::string const& strSecond, ffpp::SharedGuardT<> const& sgComplete, BrokerT::Id idRequest) { AsyncRandomString(idRequest); return std::tuple { strSecond, sgComplete }; }, [] (std::string const& strRequested, std::string const& strSecond, ffpp::SharedGuardT<> const& sgComplete, BrokerT::Id /*idChain*/) { Info::Put("Chain (3) requested string:", strRequested, ", chain (2) result :", strSecond); return sgComplete; } ) .Chain([c_idGroup] (ffpp::SharedGuardT<> const& sgComplete, BrokerT::Id idChain) { Info::Put("Finalizing chain (3) [", idChain, "]..."); BrokerT::Finalize(c_idGroup); sgComplete->Finalize(); }) .Fence() ; //Chain (1) BrokerT::Chain(c_idChain1, c_idGroup) //incomplete (reusable) chain .Request<std::string>( [] (BrokerT::Id idRequest) { AsyncRandomString(idRequest); }, [] (std::string const& strRequested, BrokerT::Id /*idChain*/) { Info::Put("Chain (1) requested string:", strRequested); return strRequested; } ) .Receive<std::string>(c_idReceive1, [sgComplete] (std::string const& strReceived, std::string const& strRequested, BrokerT::Id /*idChain*/) { Info::Put("Chain (1) received string:", strReceived); return std::vector<std::string> { strRequested, strReceived }; }) .Junction(c_idChain2) //Emitting Junction also acts like a Fence ; //Chain (2) BrokerT::Chain(c_idChain2, c_idGroup) //incomplete (reusable) chain .Junction<std::vector<std::string>>(c_idChain2, [] (std::vector<std::string> const& vFirstStrings, BrokerT::Id /*idChain*/) { Info::Put("Chain (2) received chain (1) result:", VectorToString(vFirstStrings)); }) .Request<std::string>( [] (BrokerT::Id idRequest) { AsyncRandomString(idRequest); }, [] (std::string const& strRequested, BrokerT::Id /*idChain*/) { Info::Put("Chain (2) requested string:", strRequested); return strRequested; } ) .Receive<std::string>(c_idReceive2, [sgComplete] (std::string const& strReceived, std::string const& strRequested, BrokerT::Id /*idChain*/) { Info::Put("Chain (2) received string:", strReceived); return strRequested + ", "s + strReceived; }) .Junction(c_idChain3) //Emitting Junction also acts like a Fence ; AsyncRandomString(c_idReceive1); AsyncRandomString(c_idReceive2); Info::Put("Waiting for response..."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestReceiveRequestChainLoop() { using namespace std::literals; auto const drnLoop = 30s; Accent::Put("Simulating async receive-request chain loop for", drnLoop, "..."); auto [ugJoin, sgComplete] = ffpp::BeginJoin(); BrokerT::Id const c_idReceive { L"TestReceiveRequestChainLoop.Receive" }; auto const idLoop = BrokerT::Chain<ffpp::Flags::Keep>() //chain id could be obtained from returned chainer object .Receive<bool>(c_idReceive, [] (bool bStart, BrokerT::Id idChain) { //(1) //This is not a recommended pattern (though legal), here it is used for demo/debugging purposes. if(bStart) { Info::Put("Continue..."); return GenerateRandomString(); } else { Info::Put("Stop."); BrokerT::Finalize(idChain); return "Finalized"s; } }) .Request<std::string>( [] (std::string strInitial, BrokerT::Id idRequest) { Info::Put("Initial string:", strInitial); AsyncRandomString(idRequest); return std::move(strInitial); }, [] (std::string const& strResponse, std::string const& strInitial, BrokerT::Id /*idChain*/) { Info::Put("Requested string:", strResponse); return std::tuple { strInitial, strResponse }; } ) .Chain([c_idReceive, drnLoop, tpStart = std::chrono::system_clock::now(), sgComplete = std::move(sgComplete)] ( auto const& strInitial, auto const& strResponse, auto idChain ) { Info::Put("Iteration completed with:", strInitial, strResponse); //Acquire and submit chain. This is legal in the last chain handler. BrokerT::Chain(idChain); //The better approach would be to check continuation conditions here and finalize chain as in stage (1). BrokerT::Emit(c_idReceive, std::chrono::system_clock::now() - tpStart < drnLoop); //signal continuation or finalization (1) }) .Fence() .GetChainId() ; //chain is submitted and deferred until signal (1) Info::Put("Waiting..."); SleepUpTo(2s); BrokerT::Emit(c_idReceive, true); //signal chain for start (1) ffpp::FinishJoin(sgComplete, ugJoin); Info::Put("Loop completed."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestRequestRequestChainLoop() { using namespace std::literals; auto const drnLoop = 30s; Accent::Put("Simulating async request-request chain loop for", drnLoop, "..."); auto [ugJoin, sgComplete] = ffpp::BeginJoin(); BrokerT::Chain<ffpp::Flags::Keep>() //reusable chain .Request<std::string>( [] (BrokerT::Id idRequest) { AsyncRandomString(idRequest); }, [] (std::string strResponse, BrokerT::Id /*idChain*/) { Info::Put("Requested string 1:", strResponse); return std::move(strResponse); } ) .Request<std::string>( [] (std::string strRequested1, BrokerT::Id idRequest) { AsyncRandomString(idRequest); return std::move(strRequested1); }, [] (std::string const& strResponse, std::string const& strRequested1, BrokerT::Id /*idChain*/) { Info::Put("Requested string 2:", strResponse); return std::tuple { strRequested1, strResponse }; } ) .Chain([drnLoop, tpStart = std::chrono::system_clock::now(), sgComplete = std::move(sgComplete)] ( auto const& strRequested1, auto const& strRequested2, auto idChain ) { Info::Put("Iteration completed with:", strRequested1, strRequested2); if(std::chrono::system_clock::now() - tpStart < drnLoop) BrokerT::Chain(idChain); //acquire and submit chain else BrokerT::Finalize(idChain); //finalize it }) .Fence() ; ffpp::FinishJoin(sgComplete, ugJoin); Info::Put("Loop completed."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestRequestReceiveRequestChainLoop() { using namespace std::literals; auto const drnLoop = 30s; Accent::Put("Simulating async request-receive-request chain loop for", drnLoop, "..."); auto [ugJoin, sgComplete] = ffpp::BeginJoin(); BrokerT::Id const c_idCurrentTime { L"TestRequestReceiveRequestChainLoop.CurrentTime" }; BrokerT::Chain<ffpp::Flags::Keep>() //reusable chain .Request<std::string>( [] (BrokerT::Id idRequest) { AsyncRandomString(idRequest); }, [c_idCurrentTime] (auto strResponse, auto...) { Info::Put("Requested string 1:", strResponse); //Suppose we need to get time asynchronously from somewhere... Here it is emulated by means of helper chain. BrokerT::Chain().Chain([c_idCurrentTime] (auto idChain) { SimulateLatency(idChain); BrokerT::Emit(c_idCurrentTime, std::chrono::system_clock::now()); }); return strResponse; } ) .Receive<std::chrono::system_clock::time_point>(c_idCurrentTime, [] (auto tpTime, auto strRequested1, auto...) { #if !(defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE <= 12)) Info::Put("Received current time:", tpTime); #endif return std::tuple { strRequested1, tpTime }; }) .Request<std::string>( [] (auto strRequested1, auto tpTime, BrokerT::Id idRequest) { AsyncRandomString(idRequest); return std::tuple { strRequested1, tpTime }; }, [] (auto strResponse, auto strRequested1, auto tpTime, auto...) { Info::Put("Requested string 2:", strResponse); return std::tuple { strRequested1, strResponse, tpTime }; } ) .Chain([drnLoop, tpStart = std::chrono::system_clock::now(), sgComplete = std::move(sgComplete)] ( auto strRequested1, auto strRequested2, auto tpTime, auto idChain ) { Info::Put("Iteration completed with:", strRequested1, strRequested2); if(tpTime - tpStart < drnLoop) BrokerT::Chain(idChain); //acquire and submit chain else BrokerT::Finalize(idChain); //finalize it }) .Fence() ; ffpp::FinishJoin(sgComplete, ugJoin); Info::Put("Loop completed."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestReceiveRequestReceiveRequestChainLoop() { using namespace std::literals; auto const drnLoop = 30s; Accent::Put("Simulating async receive-request-receive-request chain loop for", drnLoop, "..."); auto [ugJoin, sgComplete] = ffpp::BeginJoin(); BrokerT::Id const c_idReceiveInitialized1 { L"TestReceiveRequestReceiveRequestChainLoop.Initialized1" }, c_idReceiveInitialized2 { L"TestReceiveRequestReceiveRequestChainLoop.Initialized2" }, c_idCurrentTime { L"TestReceiveRequestReceiveRequestChainLoop.CurrentTime" }; BrokerT::Chain<ffpp::Flags::Keep>() //reusable chain //Using bool value as a permanent signal (actually the fact of identified value emission). Chain can contain multiple //signals of any context type at any point which provides capability of creating a chain's ready-to-execution barrier //(with as logical AND behavior). .Receive<ffpp::Flags::Signal, bool>(c_idReceiveInitialized1, [] (auto...) { Info::Put("Checking..."); }) .Receive<ffpp::Flags::Signal, bool>(c_idReceiveInitialized2, [] (auto...) { Info::Put("Ready for chain execution."); }) .Request<std::string>( [] (BrokerT::Id idRequest) { AsyncRandomString(idRequest); }, [c_idCurrentTime] (auto strResponse, auto...) { Info::Put("Requested string 1:", strResponse); //Suppose we need to get time asynchronously from somewhere... Here it is emulated by means of helper chain. BrokerT::Chain().Chain([c_idCurrentTime] (auto idChain) { SimulateLatency(idChain); BrokerT::Emit(c_idCurrentTime, std::chrono::system_clock::now()); }); return strResponse; } ) .Receive<std::chrono::system_clock::time_point>(c_idCurrentTime, [] (auto tpTime, auto strRequested1, auto...) { #if !(defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE <= 12)) Info::Put("Received current time:", tpTime); #endif return std::tuple { strRequested1, tpTime }; }) .Request<std::string>( [] (auto strRequested1, auto tpTime, BrokerT::Id idRequest) { AsyncRandomString(idRequest); return std::tuple { strRequested1, tpTime }; }, [] (auto strResponse, auto strRequested1, auto tpTime, auto...) { Info::Put("Requested string 2:", strResponse); return std::tuple { strRequested1, strResponse, tpTime }; } ) .Chain([drnLoop, tpStart = std::chrono::system_clock::now(), sgComplete = std::move(sgComplete)] ( auto strRequested1, auto strRequested2, auto tpTime, auto idChain ) { Info::Put("Iteration completed with:", strRequested1, strRequested2); if(tpTime - tpStart < drnLoop) BrokerT::Chain(idChain); //acquire and submit chain else BrokerT::Finalize(idChain); //finalize it }) .Fence() ; //Signal chain for initialization Info::Put("Initializing..."); SleepUpTo(2s); BrokerT::Emit(c_idReceiveInitialized1, true); SleepUpTo(2s); BrokerT::Emit(c_idReceiveInitialized2, true); ffpp::FinishJoin(sgComplete, ugJoin); Info::Put("Loop completed."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void TestReceiveRequestReceiveRequestJointChains() { using namespace std::literals; auto const drnLoop = 30s; Accent::Put("Simulating async receive-request-receive-request joint chains loop for", drnLoop, "..."); auto [ugJoin, sgComplete] = ffpp::BeginJoin(); BrokerT::Id const c_idGroup { L"ReceiveRequestReceiveRequestJointChains.Group" } , c_idReceiveInitialized0 { L"ReceiveRequestReceiveRequestJointChains.Initialized0" } , c_idReceiveInitialized1 { L"ReceiveRequestReceiveRequestJointChains.Initialized1" } , c_idReceiveInitialized2 { L"ReceiveRequestReceiveRequestJointChains.Initialized2" } , c_idReceiveContinue0 { L"ReceiveRequestReceiveRequestJointChains.Continue0" } , c_idCurrentTime { L"ReceiveRequestReceiveRequestJointChains.CurrentTime" } , c_idChain1 { L"ReceiveRequestReceiveRequestJointChains.Chain1" } , c_idChain2 { L"ReceiveRequestReceiveRequestJointChains.Chain2" } , c_idJunction2 { L"ReceiveRequestReceiveRequestJointChains.Junction2" } ; //Signal chain for initialization Info::Put("Initializing..."); BrokerT::Emit<ffpp::Flags::Junction>(c_idReceiveInitialized0, "start"s); BrokerT::Emit<ffpp::Flags::Junction>(c_idReceiveContinue0, std::tuple { true, "continue"s }); BrokerT::Chain(c_idChain1, c_idGroup) //incomplete (reusable) chain, first part of joint chains system //Using bool value as a permanent signal (actually the fact of identified value emission). Chain can contain multiple //signals of any context type at any point which provides capability of creating a chain's ready-to-execution barrier //(with as logical AND behavior). .Junction<ffpp::Flags::Signal, bool>(c_idReceiveInitialized1, [] (auto...) { Info::Put("Checking..."); }) .Junction<ffpp::Flags::Signal, std::string>(c_idReceiveInitialized0, [] (auto const& strInit, auto...) { Info::Put("Init signal:", strInit); }) .Junction<ffpp::Flags::Signal, bool>(c_idReceiveInitialized2, [] (auto...) { //[1] Info::Put("Ready for chain execution."); }) .Request<std::string>( [] (BrokerT::Id idRequest) { AsyncRandomString(idRequest, false); }, [c_idCurrentTime, sgComplete] (auto strResponse, auto...) { Info::Put("Requested string 1:", strResponse); //Suppose we need to get time asynchronously from somewhere... Here it is emulated by means of helper chain. BrokerT::Chain().Chain([c_idCurrentTime] (auto idChain) { SimulateLatency(idChain); BrokerT::Emit(c_idCurrentTime, std::chrono::system_clock::now()); }); return strResponse; } ) .Junction(c_idJunction2, c_idChain2) //[2], emitting Junction also acts like a Fence ; BrokerT::Chain(c_idChain2, c_idGroup) //reusable chain, scond part of joint chains system //Chain will be executed immediately after its construction. First stage will be invoked unconditionally which is used to //set ready to run signal for the first chain (c_idChain1), see [1]. .Chain([c_idReceiveInitialized2] (auto...) { BrokerT::Emit<ffpp::Flags::Junction>(c_idReceiveInitialized2, true); }) //This junction will be invoked only after first chain (c_idChain1) emit its result, see [2] .Junction<std::string>(c_idJunction2, [] (auto const& strRequested1, auto...) { Info::Put("Received junction argument:", strRequested1); return strRequested1; }) .Receive<std::chrono::system_clock::time_point>(c_idCurrentTime, [] (auto tpTime, auto strRequested1, auto...) { #if !(defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE <= 12)) Info::Put("Received current time:", tpTime); #endif return std::tuple { strRequested1, tpTime }; }) .Junction<ffpp::Flags::Signal, std::tuple<bool, std::string>>( c_idReceiveContinue0, [] (auto bContinue, auto const& strContinue, auto strRequested1, auto tpTime, auto...) { Info::Put("Continue signal:", bContinue, strContinue); #if !(defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE <= 12)) Info::Put("Received values:", strRequested1, tpTime); #endif return std::tuple { strRequested1, tpTime }; } ) .Request<std::string>( [] (auto strRequested1, auto tpTime, BrokerT::Id idRequest) { AsyncRandomString(idRequest, false); return std::tuple { strRequested1, tpTime }; }, [] (auto strResponse, auto strRequested1, auto tpTime, auto...) { Info::Put("Requested string 2:", strResponse); return std::tuple { strRequested1, strResponse, tpTime }; } ) .Chain([c_idChain1, c_idGroup, drnLoop, tpStart = std::chrono::system_clock::now(), sgComplete] ( auto strRequested1, auto strRequested2, auto tpTime, auto... ) { Info::Put("Iteration completed with:", strRequested1, strRequested2); if(tpTime - tpStart < drnLoop) BrokerT::Chain(c_idChain1); //acquire and submit chain else BrokerT::Finalize(c_idGroup); //finalize whole group (both chains) }) .Fence() ; SleepUpTo(2s); BrokerT::Emit<ffpp::Flags::Junction>(c_idReceiveInitialized1, true); ffpp::FinishJoin(sgComplete, ugJoin); Info::Put("Loop completed."); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv) { FFPP_TRY { Log<>::Init(algy::FilesystemOptions { algy::verbose, algy::c_bitDefaultCaps, std::filesystem::path(argv[0]).parent_path() / "log" , "chains" }); TestSimpleChain(); TestChainCache(); TestFencedChain(); TestContinuingChain(); TestRequestChain(); TestRequestStagedChain(); TestReceiveChain(); TestRequestReceiveChain(); TestReceiveRequestChain(); TestRequestReceiveJointChains(); TestReceiveRequestChainLoop(); TestRequestRequestChainLoop(); TestRequestReceiveRequestChainLoop(); TestReceiveRequestReceiveRequestChainLoop(); TestReceiveRequestReceiveRequestJointChains(); Info::Put("Finalizing..."); BrokerT::Finalize(ffpp::Flags::Wait); Accent::Put("Finished."); return 0; } FFPP_CATCH(ffpp::Base::Exception, ex) { if(Log<>::IsValid()) Fatal::Put("Top level FFPP exception:", ex); return -2; } FFPP_CATCH(std::exception, ex) { if(Log<>::IsValid()) Fatal::Put("Top level exception:", ex); return -1; } }//main