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)
This commit is contained in:
SirLynix 2024-02-04 13:43:55 +01:00
parent 44617bd14d
commit b69c0bb444
2 changed files with 6 additions and 8 deletions

View File

@ -131,7 +131,7 @@ namespace Nz
std::shuffle(randomWorkerIndices.begin(), randomWorkerIndices.end(), gen); std::shuffle(randomWorkerIndices.begin(), randomWorkerIndices.end(), gen);
} }
do while (m_running.load(std::memory_order_relaxed))
{ {
// Get a task // Get a task
TaskScheduler::Task* task; TaskScheduler::Task* task;
@ -168,7 +168,6 @@ namespace Nz
m_notifier.clear(); m_notifier.clear();
} }
} }
while (m_running.load(std::memory_order_relaxed));
} }
TaskScheduler::Task* StealTask() TaskScheduler::Task* StealTask()

View File

@ -1,8 +1,9 @@
#include <Nazara/Core/Clock.hpp>
#include <Nazara/Core/TaskScheduler.hpp> #include <Nazara/Core/TaskScheduler.hpp>
#include <catch2/catch_get_random_seed.hpp>
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#include <atomic> #include <atomic>
#include <chrono> #include <chrono>
#include <random>
#include <thread> #include <thread>
SCENARIO("TaskScheduler", "[CORE][TaskScheduler]") SCENARIO("TaskScheduler", "[CORE][TaskScheduler]")
@ -25,21 +26,19 @@ SCENARIO("TaskScheduler", "[CORE][TaskScheduler]")
WHEN("We add time-consuming tasks, they are split between workers") WHEN("We add time-consuming tasks, they are split between workers")
{ {
std::atomic_uint count = 0; std::atomic_uint count = 0;
Nz::HighPrecisionClock clock;
for (unsigned int i = 0; i < scheduler.GetWorkerCount(); ++i) for (unsigned int i = 0; i < scheduler.GetWorkerCount(); ++i)
{ {
scheduler.AddTask([&] 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++; count++;
}); });
} }
scheduler.WaitForTasks(); scheduler.WaitForTasks();
Nz::Time elapsedTime = clock.GetElapsedTime();
CHECK(count == scheduler.GetWorkerCount()); 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") WHEN("We add a lot of tasks and wait for all of them")