ソースを参照

common/thread_worker: Fix data race

FernandoS27 5 年 前
コミット
a10e112e64
2 ファイル変更18 行追加1 行削除
  1. 13 1
      src/common/thread_worker.cpp
  2. 5 0
      src/common/thread_worker.h

+ 13 - 1
src/common/thread_worker.cpp

@@ -8,9 +8,17 @@
 namespace Common {
 
 ThreadWorker::ThreadWorker(std::size_t num_workers, const std::string& name) {
+    workers_queued.store(static_cast<u64>(num_workers), std::memory_order_release);
     const auto lambda = [this, thread_name{std::string{name}}] {
         Common::SetCurrentThreadName(thread_name.c_str());
 
+        // TODO(Blinkhawk): Change the design, this is very prone to data races
+        // Wait for first request
+        {
+            std::unique_lock lock{queue_mutex};
+            condition.wait(lock, [this] { return stop || !requests.empty(); });
+        }
+
         while (!stop) {
             UniqueFunction<void> task;
             {
@@ -26,7 +34,9 @@ ThreadWorker::ThreadWorker(std::size_t num_workers, const std::string& name) {
                 requests.pop();
             }
             task();
+            work_done++;
         }
+        workers_stopped++;
         wait_condition.notify_all();
     };
     for (size_t i = 0; i < num_workers; ++i) {
@@ -49,13 +59,15 @@ void ThreadWorker::QueueWork(UniqueFunction<void> work) {
     {
         std::unique_lock lock{queue_mutex};
         requests.emplace(std::move(work));
+        work_scheduled++;
     }
     condition.notify_one();
 }
 
 void ThreadWorker::WaitForRequests() {
     std::unique_lock lock{queue_mutex};
-    wait_condition.wait(lock, [this] { return stop || requests.empty(); });
+    wait_condition.wait(
+        lock, [this] { return workers_stopped >= workers_queued || work_done >= work_scheduled; });
 }
 
 } // namespace Common

+ 5 - 0
src/common/thread_worker.h

@@ -11,6 +11,7 @@
 #include <vector>
 #include <queue>
 
+#include "common/common_types.h"
 #include "common/unique_function.h"
 
 namespace Common {
@@ -29,6 +30,10 @@ private:
     std::condition_variable condition;
     std::condition_variable wait_condition;
     std::atomic_bool stop{};
+    std::atomic<u64> work_scheduled{};
+    std::atomic<u64> work_done{};
+    std::atomic<u64> workers_stopped{};
+    std::atomic<u64> workers_queued{};
 };
 
 } // namespace Common