From f1422bf28eaaedcee9aff7dc4d93aeac2d9ce158 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sun, 24 Sep 2023 12:27:37 +0800 Subject: [PATCH] feat: multi thread executor support --- src/core/all_cases/all_cases.cc | 73 ++++++++++++++++++++++-------- src/core/all_cases/all_cases.h | 23 ++++++---- src/core/all_cases/basic_ranges.cc | 15 ++---- src/core/main.cc | 39 +++++++++++++--- 4 files changed, 107 insertions(+), 43 deletions(-) diff --git a/src/core/all_cases/all_cases.cc b/src/core/all_cases/all_cases.cc index e0e010d..9129871 100644 --- a/src/core/all_cases/all_cases.cc +++ b/src/core/all_cases/all_cases.cc @@ -1,3 +1,6 @@ +#include +#include + #include "utility.h" #include "all_cases.h" @@ -50,7 +53,7 @@ static int check_range(int head, uint32_t range) noexcept { } /// Build all valid ranges of the specified head. -void AllCases::BuildCases(int head, Ranges &basic_ranges, Ranges &release) noexcept { +void AllCases::BuildCases(int head, const Ranges &basic_ranges, Ranges &release) noexcept { release.reserve(ALL_CASES_NUM[head]); for (uint32_t index = 0; index < basic_ranges.size(); ++index) { auto offset = check_range(head, basic_ranges[index]); @@ -69,27 +72,57 @@ void AllCases::BuildCases(int head, Ranges &basic_ranges, Ranges &release) noexc } void AllCases::Build() noexcept { - if (available_) { // data already available - return; + if (available_) { + return; // reduce consumption of mutex } - if (building_.try_lock()) { // mutex lock success - if (available_) { - building_.unlock(); - return; - } - auto basic_ranges = BasicRanges::Instance().Fetch(); - for (auto head : case_heads()) { + std::lock_guard guard(building_); + if (available_) { + return; // data is already available + } + auto basic_ranges = BasicRanges::Instance().Fetch(); + for (auto head : case_heads()) { + BuildCases(head, basic_ranges, GetCases()[head]); + } + available_ = true; +} + +void AllCases::BuildParallel(Executor &&executor) noexcept { + + // TODO: mutex protect + + auto basic_ranges = BasicRanges::Instance().Fetch(); + + std::vector> fs; + + for (auto head : case_heads()) { + + auto p = std::make_shared>(); + fs.emplace_back(p->get_future()); + + executor([head, &basic_ranges, p = std::move(p)]() { + + printf("thread %d -> head = %d\n", std::this_thread::get_id(), head); +// std::cout << "thread " << std::thread::id() << " -> head = " << head << std::endl; + BuildCases(head, basic_ranges, GetCases()[head]); - } - available_ = true; - } else { - building_.lock(); // blocking waiting + + p->set_value(); + + }); + } + +// printf("all task running\n"); + + for (auto &x : fs) { + x.get(); } - building_.unlock(); // release mutex + +// printf("all task complete\n"); + } -AllRanges& AllCases::GetCases() noexcept { - static std::array cases; +MultiRanges& AllCases::GetCases() noexcept { + static MultiRanges cases; return cases; } @@ -98,10 +131,14 @@ AllCases& AllCases::Instance() noexcept { return instance; } -AllRanges& AllCases::Fetch() noexcept { +const MultiRanges& AllCases::Fetch() noexcept { this->Build(); return GetCases(); } +bool AllCases::IsAvailable() const noexcept { + return available_; +} + } // namespace cases } // namespace klotski diff --git a/src/core/all_cases/all_cases.h b/src/core/all_cases/all_cases.h index 3e528cd..d7829bb 100644 --- a/src/core/all_cases/all_cases.h +++ b/src/core/all_cases/all_cases.h @@ -45,7 +45,9 @@ namespace cases { typedef uint32_t Range; typedef std::vector Ranges; -typedef std::array AllRanges; +typedef std::array MultiRanges; + +typedef std::function&&)> Executor; constexpr auto BASIC_RANGES_NUM = 7311921; @@ -85,11 +87,15 @@ private: class AllCases { public: - -// void Build(); - void Build() noexcept; - AllRanges& Fetch() noexcept; + bool IsAvailable() const noexcept; + const MultiRanges& Fetch() noexcept; + void BuildParallel(Executor &&executor) noexcept; + + AllCases(AllCases&&) = delete; + AllCases(const AllCases&) = delete; + AllCases& operator=(AllCases&&) = delete; + AllCases& operator=(const AllCases&) = delete; static AllCases& Instance() noexcept; @@ -97,11 +103,10 @@ private: std::mutex building_; bool available_ = false; - static AllRanges& GetCases() noexcept; - static void BuildCases(int head, Ranges &basic_ranges, Ranges &release) noexcept; + AllCases() = default; + static MultiRanges& GetCases() noexcept; + static void BuildCases(int head, const Ranges &basic_ranges, Ranges &release) noexcept; }; -void demo(); - } // namespace cases } // namespace klotski diff --git a/src/core/all_cases/basic_ranges.cc b/src/core/all_cases/basic_ranges.cc index a5764c5..6791799 100644 --- a/src/core/all_cases/basic_ranges.cc +++ b/src/core/all_cases/basic_ranges.cc @@ -89,17 +89,12 @@ void BasicRanges::Build() noexcept { if (available_) { return; // reduce consumption of mutex } - if (building_.try_lock()) { // mutex lock success - if (available_) { - building_.unlock(); - return; - } - BuildRanges(GetRanges()); - available_ = true; - } else { - building_.lock(); // blocking waiting + std::lock_guard guard(building_); + if (available_) { + return; // data is already available } - building_.unlock(); // release mutex + BuildRanges(GetRanges()); + available_ = true; } Ranges& BasicRanges::GetRanges() noexcept { diff --git a/src/core/main.cc b/src/core/main.cc index 8bbb0cc..92756a4 100644 --- a/src/core/main.cc +++ b/src/core/main.cc @@ -1,12 +1,20 @@ #include +#include +#include #include "all_cases/all_cases.h" using klotski::cases::AllCases; using klotski::cases::BasicRanges; +void wkk(std::function &&f) { + f(); +} + int main() { + std::vector threads; + BasicRanges::Instance().Build(); auto start = clock(); @@ -18,14 +26,33 @@ int main() { // printf("%08X\n", x); // } - AllCases::Instance().Build(); - for (uint64_t head = 0; head < 15; ++head) { - for (auto range : AllCases::Instance().Fetch()[head]) { - printf("%09llX\n", head << 32 | range); - } - } +// BasicRanges::Instance().Build(); + + auto exec = [&threads](std::function &&f) { +// std::cout << "start exec" << std::endl; + +// f(); + auto kk = std::thread(std::move(f)); +// threads.emplace_back(std::move(kk)); + kk.detach(); + +// std::cout << "thread created" << std::endl; + }; + +// AllCases::Instance().Build(); + AllCases::Instance().BuildParallel(exec); std::cerr << ((clock() - start) * 1000 / CLOCKS_PER_SEC) << "ms" << std::endl; +// for (auto &x : threads) { +// x.join(); +// } + +// for (uint64_t head = 0; head < 15; ++head) { +// for (auto range : AllCases::Instance().Fetch()[head]) { +// printf("%09llX\n", head << 32 | range); +// } +// } + return 0; }