diff --git a/src/modules/Playerbot/Performance/ThreadPool/ThreadPool.cpp b/src/modules/Playerbot/Performance/ThreadPool/ThreadPool.cpp index 3e6aa098c..12dbfe19a 100644 --- a/src/modules/Playerbot/Performance/ThreadPool/ThreadPool.cpp +++ b/src/modules/Playerbot/Performance/ThreadPool/ThreadPool.cpp @@ -275,7 +275,8 @@ void WorkerThread::Run() // If a task was popped but an exception occurred before RecordTaskCompletion, // the pool's totalCompleted would never be updated, causing GetInFlightTasks() // to return a permanently inflated value (leading to "1 in-flight, 0 active workers") - _pool->_metrics.totalCompleted.fetch_add(1, ::std::memory_order_relaxed); + // CRITICAL: Use release ordering to synchronize with acquire loads in WaitForCompletion + _pool->_metrics.totalCompleted.fetch_add(1, ::std::memory_order_release); if (_diagnostics) { @@ -812,7 +813,8 @@ bool ThreadPool::WaitForCompletion(::std::chrono::milliseconds timeout) inFlight); // Correct the mismatch by advancing totalCompleted - _metrics.totalCompleted.fetch_add(inFlight, ::std::memory_order_relaxed); + // CRITICAL: Use release ordering to synchronize with acquire loads in WaitForCompletion + _metrics.totalCompleted.fetch_add(inFlight, ::std::memory_order_release); return true; // All work is actually done } @@ -1005,7 +1007,8 @@ void ThreadPool::RecordTaskCompletion(Task* task) auto latency = ::std::chrono::duration_cast<::std::chrono::microseconds>( completionTime - task->submittedAt).count(); - _metrics.totalCompleted.fetch_add(1, ::std::memory_order_relaxed); + // CRITICAL: Use release ordering to synchronize with acquire loads in WaitForCompletion + _metrics.totalCompleted.fetch_add(1, ::std::memory_order_release); _metrics.totalLatency.fetch_add(latency, ::std::memory_order_relaxed); // Clean up task diff --git a/src/modules/Playerbot/Performance/ThreadPool/ThreadPool.h b/src/modules/Playerbot/Performance/ThreadPool/ThreadPool.h index ca28c8eed..0e48b299c 100644 --- a/src/modules/Playerbot/Performance/ThreadPool/ThreadPool.h +++ b/src/modules/Playerbot/Performance/ThreadPool/ThreadPool.h @@ -526,7 +526,8 @@ public: ); // Update metrics - _metrics.totalSubmitted.fetch_add(1, ::std::memory_order_relaxed); + // CRITICAL: Use release ordering to synchronize with acquire loads in WaitForCompletion + _metrics.totalSubmitted.fetch_add(1, ::std::memory_order_release); size_t priorityIndex = static_cast(priority); _metrics.tasksByPriority[priorityIndex].fetch_add(1, ::std::memory_order_relaxed); @@ -549,7 +550,8 @@ public: // We already incremented totalSubmitted above, but task will not be executed. // We MUST increment totalCompleted to prevent GetInFlightTasks() from returning // a permanently inflated value, which would cause WaitForCompletion() to block forever. - _metrics.totalCompleted.fetch_add(1, ::std::memory_order_relaxed); + // CRITICAL: Use release ordering to synchronize with acquire loads in WaitForCompletion + _metrics.totalCompleted.fetch_add(1, ::std::memory_order_release); delete task; throw ::std::runtime_error("All worker queues are full");