Skip to content

Commit 8be87b2

Browse files
committed
Convert to CV and spinup counter
1 parent 57ce27e commit 8be87b2

1 file changed

Lines changed: 41 additions & 7 deletions

File tree

code/utils/threading.cpp

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,19 @@
1717

1818
namespace threading {
1919
static size_t num_threads = 1;
20+
2021
static std::condition_variable wait_for_task;
2122
static std::mutex wait_for_task_mutex;
2223
static bool wait_for_task_condition;
23-
static std::atomic_uint32_t wait_for_spindown_tasks;
24+
25+
static std::condition_variable wait_for_spindown_tasks;
26+
static std::mutex wait_for_spindown_task_mutex;
27+
static size_t wait_for_spindown_tasks_counter;
28+
29+
static std::condition_variable wait_for_spinup_tasks;
30+
static std::mutex wait_for_spinup_task_mutex;
31+
static size_t wait_for_spinup_tasks_counter;
32+
2433
static std::atomic<WorkerThreadTask> worker_task;
2534

2635
static SCP_vector<std::thread> worker_threads;
@@ -29,11 +38,21 @@ namespace threading {
2938
static void mp_worker_thread_main(size_t threadIdx) {
3039
while(true) {
3140
{
32-
//We're waiting for a new task, so spindown was successful
33-
wait_for_spindown_tasks.fetch_add(1, std::memory_order_release);
41+
std::scoped_lock lock {wait_for_spindown_task_mutex};
42+
++wait_for_spindown_tasks_counter;
43+
wait_for_spindown_tasks.notify_all();
44+
}
45+
//We're waiting for a new task, so spindown was successful
46+
{
3447
std::unique_lock<std::mutex> lk(wait_for_task_mutex);
3548
wait_for_task.wait(lk, []() { return wait_for_task_condition; });
3649
}
50+
//Notify that we passed the wait and can now start processing. This is necessary, as slow thread wakeups in very low workloads could cause the wait_for_task_condition to be false, never waking up the thread, locking on spindown wait
51+
{
52+
std::scoped_lock lock {wait_for_spinup_task_mutex};
53+
++wait_for_spinup_tasks_counter;
54+
wait_for_spinup_tasks.notify_all();
55+
}
3756

3857
switch (worker_task.load(std::memory_order_acquire)) {
3958
case WorkerThreadTask::EXIT:
@@ -148,7 +167,11 @@ namespace threading {
148167
//External Functions
149168

150169
void spin_up_threaded_task(WorkerThreadTask task) {
151-
wait_for_spindown_tasks.store(0, std::memory_order_release);
170+
{
171+
std::scoped_lock lock {wait_for_spindown_task_mutex};
172+
wait_for_spindown_tasks_counter = 0;
173+
//No notify here cause we only ever lock, never unlock the wait here.
174+
}
152175
worker_task.store(task);
153176
{
154177
std::scoped_lock lock {wait_for_task_mutex};
@@ -158,13 +181,24 @@ namespace threading {
158181
}
159182

160183
void spin_down_threaded_task() {
161-
std::scoped_lock lock {wait_for_task_mutex};
162-
wait_for_task_condition = false;
184+
//Make sure all threads are actually running before stopping the pool again
185+
{
186+
std::unique_lock<std::mutex> lk(wait_for_spinup_task_mutex);
187+
wait_for_spinup_tasks.wait(lk, []() { return wait_for_spinup_tasks_counter >= num_threads; });
188+
wait_for_spinup_tasks_counter = 0;
189+
}
190+
{
191+
std::scoped_lock lock {wait_for_task_mutex};
192+
wait_for_task_condition = false;
193+
}
163194
}
164195

165196
void spin_down_wait_complete() {
166197
//Technically, spindowns should only occur when the actual code is confirmed to be complete. So busy-waiting here is not an issue.
167-
while (wait_for_spindown_tasks.load(std::memory_order_acquire) < num_threads);
198+
{
199+
std::unique_lock<std::mutex> lk(wait_for_spindown_task_mutex);
200+
wait_for_spindown_tasks.wait(lk, []() { return wait_for_spindown_tasks_counter >= num_threads; });
201+
};
168202
}
169203

170204
void init_task_pool() {

0 commit comments

Comments
 (0)