diff --git a/dispenso/schedulable.cpp b/dispenso/schedulable.cpp index 5a670f2..f4b0f59 100644 --- a/dispenso/schedulable.cpp +++ b/dispenso/schedulable.cpp @@ -9,9 +9,31 @@ namespace dispenso { -NewThreadInvoker::ThreadWaiter& NewThreadInvoker::getWaiter() { - static ThreadWaiter waiter; - return waiter; +namespace { +std::atomic g_waiter(0); +} // namespace + +NewThreadInvoker::ThreadWaiter* NewThreadInvoker::getWaiter() { + uintptr_t waiter; + // Common case check first + if ((waiter = g_waiter.load(std::memory_order_acquire)) > 1) { + return reinterpret_cast(waiter); + } + + uintptr_t exp = 0; + if (g_waiter.compare_exchange_strong(exp, 1, std::memory_order_acq_rel)) { + g_waiter.store(reinterpret_cast(new ThreadWaiter()), std::memory_order_release); + std::atexit(destroyThreadWaiter); + } + + while ((waiter = g_waiter.load(std::memory_order_acquire)) < 2) { + } + + return reinterpret_cast(waiter); +} + +void NewThreadInvoker::destroyThreadWaiter() { + delete reinterpret_cast(g_waiter.load(std::memory_order_acquire)); } } // namespace dispenso diff --git a/dispenso/schedulable.h b/dispenso/schedulable.h index ccd8cad..23e1821 100644 --- a/dispenso/schedulable.h +++ b/dispenso/schedulable.h @@ -78,11 +78,11 @@ class NewThreadInvoker { **/ template void schedule(F&& f, ForceQueuingTag) const { - auto& waiter = getWaiter(); - waiter.add(); - std::thread thread([f = std::move(f), &waiter]() { + auto* waiter = getWaiter(); + waiter->add(); + std::thread thread([f = std::move(f), waiter]() { f(); - waiter.remove(); + waiter->remove(); }); thread.detach(); } @@ -109,7 +109,9 @@ class NewThreadInvoker { impl_.wait(0); } }; - DISPENSO_DLL_ACCESS static ThreadWaiter& getWaiter(); + DISPENSO_DLL_ACCESS static ThreadWaiter* getWaiter(); + + static void destroyThreadWaiter(); }; constexpr NewThreadInvoker kNewThreadInvoker;