#ifndef BOOST_WIN32_ONCE_CRITSEC_HPP #define BOOST_WIN32_ONCE_CRITSEC_HPP // once_critsec.hpp // // (C) Copyright 2005 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include //#include namespace boost { typedef LONG once_flag; #define BOOST_ONCE_INIT {0} namespace detail { class critsec { public: critsec() : m_Initialized(0) { } ~critsec() { if (InterlockedCompareExchange(&m_Initialized, 1, 1)) { DeleteCriticalSection(&m_critsec); } } void Init() { InitializeCriticalSection(&m_critsec); InterlockedExchange(&m_Initialized, 1); } void lock() { if (InterlockedCompareExchange(&m_Initialized, 1, 1)) { EnterCriticalSection(&m_critsec); } } void unlock() { if (InterlockedCompareExchange(&m_Initialized, 1, 1)) { LeaveCriticalSection(&m_critsec); } } private: CRITICAL_SECTION m_critsec; volatile LONG m_Initialized; }; template class scopedlock { public: scopedlock(T & lck) : m_lck(lck) { m_lck.lock(); } ~scopedlock() { m_lck.unlock(); } private: T & m_lck; }; } template void call_once(Function f,once_flag& flag) { static detail::critsec lock; static volatile LONG initialized = 0L; static volatile LONG initializing = 0L; // Have we been called before? if (!::InterlockedCompareExchange(&flag, 1, 1)) { // No, set up for the call // critical section Initialized yet? if (InterlockedCompareExchange(&initialized, 1, 1) == 0) { // No, are we initializing? if (InterlockedCompareExchange(&initializing, 1, 0) == 0) { // No, initialize the critical section and mark as initialized lock.Init(); InterlockedExchange(&initialized, 1); } else { // Yes, wait for things to be initialized do { Sleep(0); // This effectively yields to another thread/process } while(InterlockedCompareExchange(&initialized, 1, 1) == 0); } } // we have a valid critical section, so let's wait detail::scopedlock guard(lock); // We need to check again in case another thread beat us here if (!::InterlockedCompareExchange(&flag, 1, 1)) { // No, call func and set the called flag f(); ::InterlockedExchange(&flag, 1); } } } } #endif