From b69c0bb44475e1b5fb0b9a4ac1e0d007cce1f4b7 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Sun, 4 Feb 2024 13:43:55 +0100 Subject: [PATCH] Core/TaskScheduler: Fix deadlock when exiting If a worker was not given a task, it could happen to ignore the exit signal (for example if it's set before the worker started, causing it to clear the notifier boolean and test it again before checking m_running) --- src/Nazara/Core/TaskScheduler.cpp | 3 +-- tests/UnitTests/Engine/Core/TaskSchedulerTests.cpp | 11 +++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/Nazara/Core/TaskScheduler.cpp b/src/Nazara/Core/TaskScheduler.cpp index 12b054f58..6a75f1c14 100644 --- a/src/Nazara/Core/TaskScheduler.cpp +++ b/src/Nazara/Core/TaskScheduler.cpp @@ -131,7 +131,7 @@ namespace Nz std::shuffle(randomWorkerIndices.begin(), randomWorkerIndices.end(), gen); } - do + while (m_running.load(std::memory_order_relaxed)) { // Get a task TaskScheduler::Task* task; @@ -168,7 +168,6 @@ namespace Nz m_notifier.clear(); } } - while (m_running.load(std::memory_order_relaxed)); } TaskScheduler::Task* StealTask() diff --git a/tests/UnitTests/Engine/Core/TaskSchedulerTests.cpp b/tests/UnitTests/Engine/Core/TaskSchedulerTests.cpp index 772a5a678..a8be81dc0 100644 --- a/tests/UnitTests/Engine/Core/TaskSchedulerTests.cpp +++ b/tests/UnitTests/Engine/Core/TaskSchedulerTests.cpp @@ -1,8 +1,9 @@ -#include #include +#include #include #include #include +#include #include SCENARIO("TaskScheduler", "[CORE][TaskScheduler]") @@ -25,21 +26,19 @@ SCENARIO("TaskScheduler", "[CORE][TaskScheduler]") WHEN("We add time-consuming tasks, they are split between workers") { std::atomic_uint count = 0; - - Nz::HighPrecisionClock clock; for (unsigned int i = 0; i < scheduler.GetWorkerCount(); ++i) { scheduler.AddTask([&] { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::minstd_rand gen(Catch::getSeed()); + std::uniform_int_distribution dis(10, 150); + std::this_thread::sleep_for(std::chrono::milliseconds(dis(gen))); count++; }); } scheduler.WaitForTasks(); - Nz::Time elapsedTime = clock.GetElapsedTime(); CHECK(count == scheduler.GetWorkerCount()); - CHECK(elapsedTime < Nz::Time::Milliseconds(std::max(scheduler.GetWorkerCount(), 2u) * 100)); } WHEN("We add a lot of tasks and wait for all of them")