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:
parent
44617bd14d
commit
b69c0bb444
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue