From f9c6570e3b48836f582dad78075bf6c0de8b18ee Mon Sep 17 00:00:00 2001 From: ericek111 Date: Mon, 30 May 2022 15:36:50 +0200 Subject: [PATCH] prevent race condition in isIdle --- libs/MyThreadPool/include/MyThreadPool.h | 8 ++++++-- libs/MyThreadPool/include/SafePriorityQueue.h | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/libs/MyThreadPool/include/MyThreadPool.h b/libs/MyThreadPool/include/MyThreadPool.h index 36d7705..cc2732a 100644 --- a/libs/MyThreadPool/include/MyThreadPool.h +++ b/libs/MyThreadPool/include/MyThreadPool.h @@ -119,9 +119,13 @@ private: return; } - auto callable = std::move(queue.pop()); - if (callable.has_value()) { + // Prevent possible race condition in isIdle(). + // Perhaps can be reworked, e. g. by having each worker track its progress individually? + auto callable = std::move(queue.pop([&] { threadsWorking++; + })); + + if (callable.has_value()) { callable.value()(); threadsWorking--; poolCond.notify_all(); diff --git a/libs/MyThreadPool/include/SafePriorityQueue.h b/libs/MyThreadPool/include/SafePriorityQueue.h index 1bf967f..9cf52ca 100644 --- a/libs/MyThreadPool/include/SafePriorityQueue.h +++ b/libs/MyThreadPool/include/SafePriorityQueue.h @@ -41,7 +41,15 @@ public: queueLength++; } - std::optional pop() + /** + * Pop (and return) the top-most item in the stack. + * @tparam F + * @param callback Will be executed after (and only after) an element is popped off the queue, + * but before the mutex is released -- good for count-keeping. + * @return If the queue is empty, std::nullopt is returned. + */ + template + std::optional pop(F&& callback = [](){}) { std::unique_lock lock(mtx); @@ -51,10 +59,12 @@ public: queueLength--; - auto ret = std::move(queue.front()); + auto ret = std::move(queue.front().second); queue.pop_front(); - return ret.second; + callback(); + + return ret; } std::optional peek() const