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);
}
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()

View File

@ -1,8 +1,9 @@
#include <Nazara/Core/Clock.hpp>
#include <Nazara/Core/TaskScheduler.hpp>
#include <catch2/catch_get_random_seed.hpp>
#include <catch2/catch_test_macros.hpp>
#include <atomic>
#include <chrono>
#include <random>
#include <thread>
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")