Skip to content

Commit d2429c6

Browse files
authored
Merge pull request #3 from BMagnu/thread_wait_rebase
Ensure threads have spun down before continuing non-threaded execution
2 parents 6864eb1 + 468d712 commit d2429c6

3 files changed

Lines changed: 16 additions & 0 deletions

File tree

code/object/objcollide.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,7 @@ void spin_up_mp_collision() {
762762
void spin_down_mp_collision() {
763763
threading::spin_down_threaded_task();
764764
collision_processing_done.store(true);
765+
threading::spin_down_wait_complete();
765766
}
766767

767768
void queue_mp_collision(uint ctype, const obj_pair& colliding) {

code/utils/threading.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ namespace threading {
2020
static std::condition_variable wait_for_task;
2121
static std::mutex wait_for_task_mutex;
2222
static bool wait_for_task_condition;
23+
static std::atomic_uint32_t wait_for_spindown_tasks;
2324
static std::atomic<WorkerThreadTask> worker_task;
2425

2526
static SCP_vector<std::thread> worker_threads;
@@ -28,12 +29,15 @@ namespace threading {
2829
static void mp_worker_thread_main(size_t threadIdx) {
2930
while(true) {
3031
{
32+
//We're waiting for a new task, so spindown was successful
33+
wait_for_spindown_tasks.fetch_add(1, std::memory_order_release);
3134
std::unique_lock<std::mutex> lk(wait_for_task_mutex);
3235
wait_for_task.wait(lk, []() { return wait_for_task_condition; });
3336
}
3437

3538
switch (worker_task.load(std::memory_order_acquire)) {
3639
case WorkerThreadTask::EXIT:
40+
//We're done and will quit, so ensure we report this.
3741
return;
3842
case WorkerThreadTask::COLLISION:
3943
collide_mp_worker_thread(threadIdx);
@@ -144,6 +148,7 @@ namespace threading {
144148
//External Functions
145149

146150
void spin_up_threaded_task(WorkerThreadTask task) {
151+
wait_for_spindown_tasks.store(0, std::memory_order_release);
147152
worker_task.store(task);
148153
{
149154
std::scoped_lock lock {wait_for_task_mutex};
@@ -157,6 +162,11 @@ namespace threading {
157162
wait_for_task_condition = false;
158163
}
159164

165+
void spin_down_wait_complete() {
166+
//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);
168+
}
169+
160170
void init_task_pool() {
161171
if (Cmdline_multithreading == 0) {
162172
//At least given the current collision-detection threading, 8 cores (if available) seems like a sweetspot, with more cores adding too much overhead.
@@ -181,6 +191,8 @@ namespace threading {
181191
void shut_down_task_pool() {
182192
spin_up_threaded_task(WorkerThreadTask::EXIT);
183193

194+
//Technically we could await spin_down_wait_complete here, but since we're returning and joining the threads here, there is no need
195+
184196
for(auto& thread : worker_threads) {
185197
thread.join();
186198
}

code/utils/threading.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ namespace threading {
1111
//This _must_ be called on the main thread BEFORE a task completes on a thread of the task pool.
1212
void spin_down_threaded_task();
1313

14+
//This should be called AFTER the command to finish a given task is given. This will block until all threads have returned into a state where they are able to listen to new commands.
15+
void spin_down_wait_complete();
16+
1417
void init_task_pool();
1518
void shut_down_task_pool();
1619

0 commit comments

Comments
 (0)