< Previous by Date | Date Index | Next by Date > |
< Previous in Thread | Thread Index | Next in Thread > |
Hi everybody, I just upgraded to the latest code version and got a problem with static initialization order. In the message below, Daniel pointed out that the static initialization order is not reliable. Please have a look at this call stack: xxx.tsp!takeLock(resip::Lockable & lockable, resip::LockType lockType) Line 30 + 0x3 bytes C++ xxx.tsp!resip::Lock::Lock(resip::Lockable & lockable, resip::LockType lockType) Line 39 + 0xd bytes C++ xxx.tsp!resip::ThreadIf::tlsKeyCreate(unsigned long & key, void (void *)* destructor) Line 234 C++ xxx.tsp!resip::LogStaticInitializer::LogStaticInitializer() Line 87 + 0x10 bytes C++ xxx.tsp!resip::`dynamic initializer for '_staticLogInit''() Line 426 + 0xd bytes C++ msvcr100d.dll!_initterm(void (void)* * pfbegin, void (void)* * pfend) Line 873 C xxx.tsp!_CRT_INIT(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 284 + 0xf bytes C xxx.tsp!__DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 506 + 0x11 bytes C xxx.tsp!_DllMainCRTStartup(void * hDllHandle, unsigned long dwReason, void * lpreserved) Line 476 + 0x11 bytes C LogStaticInitializer is instantiated and calls tlsKeyCreate. tlsKeyCreate tries to do Lock lock(*mTlsDestructorsMutex); But at this time mTlsDestructorsMutex is NULL because static TlsDestructorInitializer _staticTlsInit; has not been initialized yet. (TlsDestructorInitializer creates mTlsDestructorsMutex) How should I work around this problem? I added TlsDestructorInitializer tlsDestructorInitializer; as a private member to LogStaticInitializer and this made it work, but I am not sure if that's the best strategy...? TlsDestructorInitializer seems to be used as a singleton (static TlsDestructorInitializer _staticTlsInit), but its implementation is obviously prepared to deal with multiple instances. Another option to control static initialization order would be init_seg (http://msdn.microsoft.com/en-us/library/7977wcck%28VS.80%29.aspx), but it’s specific to Visual Studio… Best regards, Matthias -----Original Message----- I'm not convinced it is safe: a) you can't be sure about the order that static initialization is done - some other static initialization code in another translation unit depending on this static object could execute before it is in a good state b) although it may not be normal practice within this code, can you be certain that no other static initializer starts a thread? On 01/08/11 00:38, Aron Rosenberg wrote: > I was referring to the ThreadIf stuff as safe since its indirectly > only initialized during global static initialization. It would unsafe > during regular runtime as you mentioned. > > Aron Rosenberg > Sr. Director, Engineering, > LifeSize, a division of Logitech > > > > > On Sat, Jul 30, 2011 at 11:15 AM, Byron Campen <bcampen@xxxxxxxxxxxx> wrote: > >> Actually, this too can be problematic, because you can get multiple >> initializations of the Mutex if multiple threads try to construct the >> same type of object at once. And, if you have any static functions >> that try to use the mutex, you're sunk because it might not be >> initialized. A better way to do this is the following: >> >> In the header: >> >> class FoobaJooba >> { >> static Mutex& getMutex() >> { >> static Mutex mMutex; >> return mMutex; >> } >> >> // Nobody should actually touch this, or use it to try to determine >> // whether the mutex has been initialized; this bool could be >> anything // during static initialization. It exists solely to cause >> getMutex() // to be called sometime during static init. >> static bool ensureInitialized; >> }; >> >> In the implementation file: >> >> bool FoobaJooba::ensureInitialized=(&initMutex()!=0); >> >> This ensures that getMutex() is called sometime during static >> initialization (it might be called multiple times, but this is ok, >> since there is only one thread of execution), so multiple init >> problems don't crop up, and it also ensures that if somebody tries to >> access the mutex during static init _before_ ensureInitialized has >> been initialized, the mutex is just initialized a little bit early. >> >> Now, this is still not perfect; it doesn't prevent nastiness during >> static _de_initilization. >> >> Best regards, >> Byron Campen >> >> >> Best regards, >> Byron Campen >> >> The best way to handle this is actually to make the mutex be a static >> pointer which gets allocated during a class constructor. See ThreadIf >> class and mTlsDestructorsMutex and friends for the best way to implement this. >> >> -Aron >> >> Aron Rosenberg >> LifeSize, a division of Logitech >> >> >> On Thu, Jul 21, 2011 at 11:25 AM, Daniel Pocock < >> daniel@xxxxxxxxxxxxxxxxxxxxx> wrote: >> >>> >>> >>> >>> I notice a few places where a Mutex objected is constructed, >>> typically as a static member of a class: >>> >>> $ grep Mutex rutil/*.hxx | grep static >>> Log.hxx: static Mutex _mutex; >>> Random.hxx: static Mutex mMutex; >>> Time.hxx: static Mutex mWrapCounterMutex; >>> Time.hxx: static Mutex mMutex; >>> >>> The order in which the constructors of these objects are called is >>> non-deterministic >>> >>> It is actually possible that an code section depending on the Mutex >>> could be attempting to lock on the Mutex before the Mutex itself is >>> initialized >>> >>> >>> >>> For UNIX, it may be possible to initialize Mutex::mId = >>> PTHREAD_MUTEX_INITIALIZER, or even define Mutex like so: >>> >>> #define STATIC_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER typedef >>> pthread_mutex_t Mutex; >>> >>> and then in some file.cxx: >>> >>> Mutex mMutex = STATIC_MUTEX_INIT; >>> >>> >>> >>> However, the situation for Windows is not quite the same: >>> >>> http://locklessinc.com/articles/pthreads_on_windows/ >>> >>> suggests a hack: >>> >>> #define PTHREAD_MUTEX_INITIALIZER {(void*)-1,-1,0,0,0,0} >>> >>> that depends on the internal structure of the Windows type >>> CRITICAL_SECTION >>> >>> Has anyone else got any thoughts on this, how it should be done on >>> Windows, and any other platform considerations that I haven't raised? >>> >>> >>> >>> _______________________________________________ >>> resiprocate-devel mailing list >>> resiprocate-devel@xxxxxxxxxxxxxxx >>> https://list.resiprocate.org/mailman/listinfo/resiprocate-devel >>> >> >> _______________________________________________ >> resiprocate-devel mailing list >> resiprocate-devel@xxxxxxxxxxxxxxx >> https://list.resiprocate.org/mailman/listinfo/resiprocate-devel >> >> >> > _______________________________________________ resiprocate-devel mailing list resiprocate-devel@xxxxxxxxxxxxxxx https://list.resiprocate.org/mailman/listinfo/resiprocate-devel |