< 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-----
From: resiprocate-devel-bounces@xxxxxxxxxxxxxxx [mailto:resiprocate-devel-bounces@xxxxxxxxxxxxxxx] On Behalf Of Daniel Pocock
Sent: Montag, 1. August 2011 00:54
To: Aron Rosenberg
Cc: resiprocate-devel@xxxxxxxxxxxxxxx
Subject: Re: [reSIProcate] unsafe static Mutex object initialization
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
_______________________________________________
resiprocate-devel mailing list
resiprocate-devel@xxxxxxxxxxxxxxx
https://list.resiprocate.org/mailman/listinfo/resiprocate-devel