Skip to content

Commit

Permalink
ThreadBack: EntryFN ret SafePtr<void> than bool
Browse files Browse the repository at this point in the history
  • Loading branch information
fchn289 committed Aug 5, 2024
1 parent 6447cd0 commit ded1cae
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 48 deletions.
2 changes: 1 addition & 1 deletion src/thread/AsyncBack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ bool AsyncBack::newTaskOK(const MT_TaskEntryFN& mt_aEntryFN, const TaskBackFN& a
launch::async,
[mt_aEntryFN, this]() // must cp than ref, otherwise dead loop
{
const bool ret = mt_aEntryFN();
auto ret = mt_aEntryFN();
this->nDoneTh_.fetch_add(1, std::memory_order_relaxed); // fastest +1
mt_pingMainTH();
return ret;
Expand Down
4 changes: 2 additions & 2 deletions src/thread/ThPoolBack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ ThPoolBack::ThPoolBack(size_t aMaxThread)
{ // thread main()
for (;;)
{
packaged_task<bool()> task;
packaged_task<SafePtr<void>()> task;
{
unique_lock<mutex> lock(this->mutex_);
this->cv_.wait(lock, [this]{ return this->stopAllTH_ || !this->taskQ_.empty(); });
Expand Down Expand Up @@ -68,7 +68,7 @@ bool ThPoolBack::newTaskOK(const MT_TaskEntryFN& mt_aEntryFN, const TaskBackFN&
if (! ThreadBack::newTaskOK(mt_aEntryFN, aBackFN, oneLog))
return false;

packaged_task<bool()> task(mt_aEntryFN); // packaged_task can get_future()="task result"
packaged_task<SafePtr<void>()> task(mt_aEntryFN); // packaged_task can get_future()="task result"
fut_backFN_S_.emplace_back(task.get_future(), aBackFN); // save future<> & aBackFN()
{
unique_lock<mutex> lock(mutex_);
Expand Down
2 changes: 1 addition & 1 deletion src/thread/ThPoolBack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ThPoolBack : public ThreadBack
private:
// -------------------------------------------------------------------------------------------
std::vector<std::thread> thPool_;
std::deque<std::packaged_task<bool()>> taskQ_;
std::deque<std::packaged_task<SafePtr<void>()>> taskQ_;

std::mutex mutex_;
std::condition_variable cv_;
Expand Down
14 changes: 10 additions & 4 deletions src/thread/ThreadBack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@
* SPDX-License-Identifier: BSD-3-Clause
*/
// ***********************************************************************************************
// - Why:
// - Why this class:
// . support both async() & thread pool
// . common here, special in AsyncBack or ThPoolBack
//
// - why SafePtr
// . thread can ret any type data include bool
// . safe convert from SafePtr<void> to correct data
// ***********************************************************************************************
#pragma once

Expand All @@ -17,16 +21,17 @@
#include <utility>

#include "MT_PingMainTH.hpp"
#include "SafePtr.hpp"
#include "UniLog.hpp"

#define THREAD_BACK (rlib::ObjAnywhere::getObj<rlib::ThreadBack>())

namespace rlib
{
// ***********************************************************************************************
using MT_TaskEntryFN = std::function<bool()>; // succ ret true, otherwise false
using TaskBackFN = std::function<void(bool)>; // entry ret as para
using StoreThreadBack = std::list<std::pair<std::future<bool>, TaskBackFN> >; // deque rm middle is worse
using MT_TaskEntryFN = std::function<SafePtr<void>()>; // ret-nullptr means failure
using TaskBackFN = std::function<void(SafePtr<void>)>; // MT_TaskEntryFN's ret as para
using StoreThreadBack = std::list<std::pair<std::future<SafePtr<void>>, TaskBackFN> >; // deque is worse when rm mid

// ***********************************************************************************************
class ThreadBack
Expand Down Expand Up @@ -65,4 +70,5 @@ class ThreadBack
// .......... ......... .......................................................................
// 2024-07-09 CSZ 1)create
// 2024-08-05 CSZ - nDoneTh_ to improve iteration of fut_backFN_S_
// - MT_TaskEntryFN ret SafePtr<void> instead of bool
// ***********************************************************************************************
2 changes: 1 addition & 1 deletion src/thread/ThreadBackViaMsgSelf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ TaskBackFN viaMsgSelf(const TaskBackFN& aBackFN, std::shared_ptr<MsgSelf> aMsgSe
{
return ! aBackFN || aMsgSelf == nullptr
? TaskBackFN(nullptr) // empty fn
: [aBackFN, aMsgSelf, aPri](bool aRet) // must cp aBackFN since lambda run later in diff lifecycle
: [aBackFN, aMsgSelf, aPri](SafePtr<void> aRet) // must cp aBackFN since lambda run later in diff lifecycle
{
aMsgSelf->newMsg(bind(aBackFN, aRet), aPri); // wrap aBackFN to queue in MsgSelf
};
Expand Down
12 changes: 6 additions & 6 deletions ut/thread/ThPoolBackTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ TEST_F(ThPoolBackTest, invalid_maxThread)
{
ThPoolBack myPool(0); // invalid maxThread=0
EXPECT_TRUE(threadBack_.newTaskOK(
[] { return true; }, // entryFn
[](bool) {} // backFn
[] { return make_safe<bool>(true); }, // entryFn
[](SafePtr<void>) {} // backFn
)) << "REQ: can create new task";
while (threadBack_.hdlFinishedTasks() == 0)
timedwait(); // REQ: wait new task done
Expand All @@ -30,9 +30,9 @@ TEST_F(ThPoolBackTest, performance)
[] // entryFn
{
this_thread::yield(); // hung like real time-cost task
return true;
return make_safe<bool>(true);
},
[](bool) {} // backFn
[](SafePtr<void>) {} // backFn
));
for (size_t nHandled = 0; nHandled < maxThread; nHandled += thPoolBack.hdlFinishedTasks())
timedwait();
Expand All @@ -48,9 +48,9 @@ TEST_F(ThPoolBackTest, performance)
[] // entryFn
{
this_thread::yield(); // hung like real time-cost task
return true;
return make_safe<bool>(true);
},
[](bool) {} // backFn
[](SafePtr<void>) {} // backFn
));
for (size_t nHandled = 0; nHandled < maxThread; nHandled += asyncBack.hdlFinishedTasks())
timedwait();
Expand Down
61 changes: 28 additions & 33 deletions ut/thread/ThreadBackTest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,27 +58,22 @@ TEST_F(THREAD_BACK_TEST, GOLD_entryFn_inNewThread_thenBackFn_inMainThread_withTi
EXPECT_TRUE(ThreadBack::inMyMainTH()) << "REQ: OK in main thread";
EXPECT_TRUE(threadBack_.newTaskOK(
// MT_TaskEntryFN
[this]() -> bool
[this]()
{
EXPECT_FALSE(ThreadBack::inMyMainTH()) << "REQ: in new thread";
return true;
return make_safe<bool>(true);
},
// TaskBackFN
[this](bool)
[this](SafePtr<void>)
{
EXPECT_TRUE(ThreadBack::inMyMainTH()) << "REQ: in main thread";
}
));

while (true)
while (threadBack_.hdlFinishedTasks() == 0)
{
if (threadBack_.hdlFinishedTasks() == 0)
{
INF("new thread not end yet...");
timedwait(); // REQ: timedwait() is more efficient than keep hdlFinishedTasks()
continue;
}
return;
INF("new thread not end yet...");
timedwait(); // REQ: timedwait() is more efficient than keep hdlFinishedTasks()
}
}
TEST_F(THREAD_BACK_TEST, GOLD_entryFnResult_toBackFn_withoutTimedWait)
Expand All @@ -89,14 +84,14 @@ TEST_F(THREAD_BACK_TEST, GOLD_entryFnResult_toBackFn_withoutTimedWait)
SCOPED_TRACE(idxThread);
EXPECT_TRUE(threadBack_.newTaskOK(
// MT_TaskEntryFN
[idxThread]() -> bool
[idxThread]()
{
return idxThread % 2 != 0; // ret true / false
return make_safe<bool>(idxThread % 2 != 0); // ret true / false
},
// TaskBackFN
[idxThread](bool aRet)
[idxThread](SafePtr<void> aRet)
{
EXPECT_EQ(idxThread % 2 != 0, aRet) << "REQ: check true & false";
EXPECT_EQ(idxThread % 2 != 0, *(dynamic_pointer_cast<bool>(aRet).get())) << "REQ: check true & false";
}
));
}
Expand All @@ -112,24 +107,24 @@ TEST_F(THREAD_BACK_TEST, canHandle_someThreadDone_whileOtherRunning)
atomic<bool> canEnd(false);
threadBack_.newTaskOK(
// MT_TaskEntryFN
[&canEnd]() -> bool
[&canEnd]()
{
while (not canEnd)
this_thread::yield(); // not end until instruction
return true;
return make_safe<bool>(true);
},
// TaskBackFN
[](bool) {}
[](SafePtr<void>) {}
);

threadBack_.newTaskOK(
// MT_TaskEntryFN
[]() -> bool
[]()
{
return false; // quick end
return make_safe<bool>(false); // quick end
},
// TaskBackFN
[](bool) {}
[](SafePtr<void>) {}
);

while (threadBack_.hdlFinishedTasks() == 0)
Expand All @@ -152,8 +147,8 @@ TEST_F(THREAD_BACK_TEST, GOLD_entryFn_notify_insteadof_timeout)
{
auto start = high_resolution_clock::now();
threadBack_.newTaskOK(
[] { return true; }, // entryFn
[](bool) {} // backFn
[] { return make_safe<bool>(true); }, // entryFn
[](SafePtr<void>) {} // backFn
);
timedwait(0, 500'000'000); // long timer to ensure thread done beforehand
auto dur = duration_cast<std::chrono::milliseconds>(high_resolution_clock::now() - start);
Expand All @@ -173,16 +168,16 @@ TEST_F(THREAD_BACK_TEST, emptyThreadList_ok)
TEST_F(THREAD_BACK_TEST, invalid_msgSelf_entryFN_backFN)
{
EXPECT_FALSE(threadBack_.newTaskOK(
[] { return true; }, // entryFn
viaMsgSelf([](bool) {}, nullptr) // invalid since msgSelf==nullptr
[] { return make_safe<bool>(true); }, // entryFn
viaMsgSelf([](SafePtr<void>) {}, nullptr) // invalid since msgSelf==nullptr
));
EXPECT_FALSE(threadBack_.newTaskOK(
[] { return true; }, // entryFn
[] { return make_safe<bool>(true); }, // entryFn
viaMsgSelf(nullptr, msgSelf_) // invalid since backFn==nullptr
));
EXPECT_FALSE(threadBack_.newTaskOK(
MT_TaskEntryFN(nullptr), // invalid since entryFn==nullptr
[](bool) {} // backFn
[](SafePtr<void>) {} // backFn
));
EXPECT_EQ(0, threadBack_.nThread());
}
Expand Down Expand Up @@ -223,13 +218,13 @@ TEST_F(THREAD_BACK_TEST, GOLD_integrate_MsgSelf_ThreadBack_MtInQueue) // simula
// entryFn
[] {
mt_getQ().mt_push(MAKE_PTR<string>("a"));
return true;
return make_safe<bool>(true);
},
// backFn
viaMsgSelf( // REQ: via MsgSelf
[this, &cb_info](bool aRet)
[this, &cb_info](SafePtr<void> aRet)
{
EXPECT_TRUE(aRet) << "entryFn succ";
EXPECT_TRUE(*(dynamic_pointer_cast<bool>(aRet).get())) << "entryFn succ";
cb_info.emplace("REQ: a's backFn via MsgSelf");
},
msgSelf_
Expand All @@ -239,13 +234,13 @@ TEST_F(THREAD_BACK_TEST, GOLD_integrate_MsgSelf_ThreadBack_MtInQueue) // simula
// entryFn
[] {
mt_getQ().mt_push(MAKE_PTR<int>(2));
return true;
return make_safe<bool>(true);
},
// backFn
viaMsgSelf(
[this, &cb_info](bool aRet)
[this, &cb_info](SafePtr<void> aRet)
{
EXPECT_TRUE(aRet) << "entryFn succ";
EXPECT_TRUE(*(dynamic_pointer_cast<bool>(aRet).get())) << "entryFn succ";
cb_info.emplace("REQ: 2's backFn via MsgSelf");
},
msgSelf_
Expand Down

0 comments on commit ded1cae

Please sign in to comment.