From 8250d82428e2730dc0620aeed24f43c9d0b4029a Mon Sep 17 00:00:00 2001 From: Stuart Hayhurst Date: Mon, 5 Feb 2024 02:50:27 +0000 Subject: [PATCH] In debug mode, check work queue is empty, and the job counter matches --- src/ammonite/core/threadManager.cpp | 34 +++++++++++++++++++++++++++++ src/ammonite/core/threadManager.hpp | 10 +++++++++ src/threadDemo.cpp | 12 +++++++++- 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/ammonite/core/threadManager.cpp b/src/ammonite/core/threadManager.cpp index c336c98..0d5164a 100644 --- a/src/ammonite/core/threadManager.cpp +++ b/src/ammonite/core/threadManager.cpp @@ -4,6 +4,7 @@ #include #include "../types.hpp" +#include "../utils/debug.hpp" #define MAX_EXTRA_THREADS 512 @@ -171,6 +172,31 @@ namespace ammonite { } } +#ifdef DEBUG + bool debugCheckRemainingWork(bool verbose) { + bool issuesFound = false; + + workQueueMutex.lock(); + if (workQueue.size() != 0) { + issuesFound = true; + if (verbose) { + ammoniteInternalDebug << "WARNING: Work queue not empty" << std::endl; + } + } + + if (workQueue.size() != (unsigned)jobCount) { + issuesFound = true; + if (verbose) { + ammoniteInternalDebug << "WARNING: Work queue size and job count don't match" \ + << std::endl; + } + } + workQueueMutex.unlock(); + + return issuesFound; + } +#endif + //Finish work already in the queue and kill the threads void destroyThreadPool() { //Finish existing work and block new work from starting @@ -187,6 +213,14 @@ namespace ammonite { threadPool[i].thread.join(); } +/* In debug mode, check that the queue is empty, and matches the job counter + - If it doesn't, it's not technically a bug, but in practice it will be, as work + that was expected to be finished wasn't +*/ +#ifdef DEBUG + debugCheckRemainingWork(true); +#endif + //Reset remaining data delete[] threadPool; extraThreadCount = 0; diff --git a/src/ammonite/core/threadManager.hpp b/src/ammonite/core/threadManager.hpp index e3c858c..cce0ae3 100644 --- a/src/ammonite/core/threadManager.hpp +++ b/src/ammonite/core/threadManager.hpp @@ -21,4 +21,14 @@ namespace ammonite { } } +#ifdef DEBUG +namespace ammonite { + namespace thread { + namespace internal { + bool debugCheckRemainingWork(bool verbose); + } + } +} +#endif + #endif diff --git a/src/threadDemo.cpp b/src/threadDemo.cpp index 832d1ea..4730cef 100644 --- a/src/threadDemo.cpp +++ b/src/threadDemo.cpp @@ -12,7 +12,9 @@ static void shortTask(void*) { } int main() { + bool passed = true; ammonite::utils::Timer runTimer; + if (ammonite::thread::internal::createThreadPool(0) == -1) { ammonite::utils::error << "Failed to create thread pool, exiting" << std::endl; return EXIT_FAILURE; @@ -39,5 +41,13 @@ int main() { //Clean up and exit ammonite::thread::internal::destroyThreadPool(); - return EXIT_SUCCESS; + + //Check work queue is empty, and job counter is also 0 (debug mode) +#ifdef DEBUG + if (ammonite::thread::internal::debugCheckRemainingWork(false)) { + passed = false; + } +#endif + + return passed ? EXIT_SUCCESS : EXIT_FAILURE; }