From b905d7fbc606bfb887146450c03dc484f6af5863 Mon Sep 17 00:00:00 2001 From: howsohazard <143410553+howsohazard@users.noreply.github.com> Date: Tue, 6 Aug 2024 13:18:09 -0400 Subject: [PATCH] 21153: Improves strictness of condition variables, improving stability on Apple platforms and when compiled with CLANG (#214) --- src/Amalgam/ThreadPool.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Amalgam/ThreadPool.h b/src/Amalgam/ThreadPool.h index 6f55e0ea..8ddf7a93 100644 --- a/src/Amalgam/ThreadPool.h +++ b/src/Amalgam/ThreadPool.h @@ -297,7 +297,8 @@ class ThreadPool //increments the number of tasks by num_new_tasks inline void AddTask(size_t num_new_tasks = 1) { - numTasks.fetch_add(num_new_tasks); + std::unique_lock lock(mutex); + numTasks += num_new_tasks; } //returns when all the tasks have been completed @@ -310,24 +311,22 @@ class ThreadPool //marks one task as completed inline void MarkTaskCompleted() { - size_t prev_tasks_completed = numTasksCompleted.fetch_add(1); - if(prev_tasks_completed + 1 == numTasks) - { - //in theory, this lock may not be necessary, but in practice it is to prevent deadlock - std::unique_lock lock(mutex); + std::unique_lock lock(mutex); + if(++numTasksCompleted == numTasks) condVar.notify_all(); - } } //marks one task as completed, but can be called from the thread setting up the tasks inline void MarkTaskCompletedBeforeWaitForTasks() { - numTasksCompleted.fetch_add(1); + std::unique_lock lock(mutex); + numTasksCompleted++; } protected: - std::atomic numTasks; - std::atomic numTasksCompleted; + //the counters are not atomic as the condVar needs a mutex around any change of value anyway + size_t numTasks; + size_t numTasksCompleted; std::mutex mutex; std::condition_variable condVar; };