📄 once.cpp
字号:
// Copyright (C) 2001// William E. Kempf//// Permission to use, copy, modify, distribute and sell this software// and its documentation for any purpose is hereby granted without fee,// provided that the above copyright notice appear in all copies and// that both that copyright notice and this permission notice appear// in supporting documentation. William E. Kempf makes no representations// about the suitability of this software for any purpose.// It is provided "as is" without express or implied warranty.#include <boost/thread/once.hpp>#include <cstdio>#include <cassert>#if defined(BOOST_HAS_WINTHREADS)# include <windows.h># if defined(BOOST_NO_STRINGSTREAM)# include <strstream> class unfreezer { public: unfreezer(std::ostrstream& s) : m_stream(s) {} ~unfreezer() { m_stream.freeze(false); } private: std::ostrstream& m_stream; };# else# include <sstream># endif#elif defined(BOOST_HAS_MPTASKS)# include <Multiprocessing.h>#endif#ifdef BOOST_NO_STDC_NAMESPACE namespace std { using ::sprintf; }#endif#if defined(BOOST_HAS_PTHREADS)namespace {pthread_key_t key;pthread_once_t once = PTHREAD_ONCE_INIT;typedef void (*once_callback)();}extern "C" {static void key_init(){ pthread_key_create(&key, 0);}static void do_once(){ once_callback* cb = reinterpret_cast<once_callback*>(pthread_getspecific(key)); (**cb)();}}#elif defined(BOOST_HAS_MPTASKS)namespace { void *remote_call_proxy(void *pData) { std::pair<void (*)(), boost::once_flag *> &rData(*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData)); if(*rData.second == false) { rData.first(); *rData.second = true; } return(NULL); }}#elif defined(BOOST_HAS_WINTHREADS)namespace { // The signature for InterlockedCompareExchange has changed with the // addition of Win64 support. I can't determine any (consistent and // portable) way of using conditional compilation to detect this, so // we use these type wrappers. Unfortunately, the various vendors // use different calling conventions and other signature anamolies, // and thus have unique types as well. This is known to work on VC6, // VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for // other platforms? inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG), volatile LONG* dest, LONG exch, LONG cmp) { return (*ice)(const_cast<LONG*>(dest), exch, cmp); } inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG), volatile LONG* dest, LONG exch, LONG cmp) { return (*ice)(dest, exch, cmp); } inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID), volatile LONG* dest, LONG exch, LONG cmp) { return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp); } // The friendly form of InterlockedCompareExchange that defers // according to the above function type wrappers. inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp) { return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp); }}#endifnamespace boost {void call_once(void (*func)(), once_flag& flag){#if defined(BOOST_HAS_WINTHREADS) if (compare_exchange(&flag, 1, 1) == 0) {#if defined(BOOST_NO_STRINGSTREAM) std::ostrstream strm; strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag << std::ends; unfreezer unfreeze(strm); HANDLE mutex = CreateMutex(NULL, FALSE, strm.str());#else std::ostringstream strm; strm << "2AC1A572DB6944B0A65C38C4140AF2F4" << std::hex << GetCurrentProcessId() << &flag; HANDLE mutex = CreateMutex(NULL, FALSE, strm.str().c_str());#endif assert(mutex != NULL); int res = 0; res = WaitForSingleObject(mutex, INFINITE); assert(res == WAIT_OBJECT_0); if (compare_exchange(&flag, 1, 1) == 0) { func(); InterlockedExchange(&flag, 1); } res = ReleaseMutex(mutex); assert(res); res = CloseHandle(mutex); assert(res); }#elif defined(BOOST_HAS_PTHREADS) pthread_once(&once, &key_init); pthread_setspecific(key, &func); pthread_once(&flag, do_once);#elif defined(BOOST_HAS_MPTASKS) if(flag == false) { // all we do here is make a remote call to blue, as blue is not reentrant. std::pair<void (*)(), once_flag *> sData(func, &flag); MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext); assert(flag == true); }#endif}}// Change Log:// 1 Aug 01 WEKEMPF Initial version.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -