diff --git i/include/ppqsort/parallel/cpp/thread_pool.h w/include/ppqsort/parallel/cpp/thread_pool.h
--- i/include/ppqsort/parallel/cpp/thread_pool.h
+++ w/include/ppqsort/parallel/cpp/thread_pool.h
@@ -134,7 +134,9 @@ namespace ppqsort::impl::cpp {
             alignas(parameters::cacheline_size) std::atomic<std::size_t> pending_tasks_{0};
             alignas(parameters::cacheline_size) std::atomic<std::size_t> total_tasks_{0};
             alignas(parameters::cacheline_size) std::atomic<bool> to_stop_{false};
-            std::binary_semaphore threads_done_semaphore_{0};   // used to wait for all tasks to finish
+            // counting_semaphore: multiple workers may concurrently observe total_tasks_ == 0
+            // and call release(); a binary_semaphore would assert when the count exceeds 1.
+            std::counting_semaphore<> threads_done_semaphore_{0};
             std::mutex mtx_priority_;
             bool stopped = false;
     };
