//SPDX-License-Identifier: LGPL-3.0-only //SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® // ThreadPool::Stop ends the pool for everyone in it, the thread that joined // it with JoinPool too. Stop woke and joined the worker threads only, so a // JoinPool caller slept on, never told. And Stop called again joined threads // already joined, which throws. // // Here another thread stops the pool this one has joined, then stops it // again. A watchdog fails the test if JoinPool doesn't return. #include #include import Crafter.Thread; import std; using namespace Crafter; using namespace std::chrono_literals; int main() { std::thread watchdog([] { std::this_thread::sleep_for(10s); std::println("FAIL JoinPool didn't return within 10 s of Stop"); _exit(EXIT_FAILURE); }); watchdog.detach(); ThreadPool::Start(4); std::atomic ran = 0; for (int i = 0; i < 100; ++i) ThreadPool::Enqueue([&ran] { ++ran; }); std::thread stopper([] { std::this_thread::sleep_for(100ms); ThreadPool::Stop(); }); ThreadPool::JoinPool(); stopper.join(); std::println("{} Stop from another thread ends the JoinPool of the thread that joined, after the queued tasks ({} of 100)", ran == 100 ? "PASS" : "FAIL", ran.load()); ThreadPool::Stop(); std::println("PASS and stopping it again does nothing"); return ran == 100 ? EXIT_SUCCESS : EXIT_FAILURE; }