I have ran into a situation that is very werid. Could anyone help me
This a C++ application built and debugged on Visual Studio .Net 2005. Basically I'm implementing a singleton class using double check locking pattern. I have read many arcticles about how this pattern is not thread safe, but my problem is slightly different. Here is the pseudo code:
MyMutex.h/cpp
class MyMutex {
public:
...
Lock() {
...
}
Unlock() {
...
}
...
};
ThreadMutex.h/cpp
class ThreadMutex {
public:
ThreadMutex() {
...
_lock = new MyMutex();
...
}
Acquire() {
...
_lock->Lock();
...
}
Release() {
...
_lock->Unlock();
...
}
...
private:
MyMutex* _lock;
}
MyObject.h
class MyObject {
protected:
MyObject();
...
public:
static MyObject Instance()
private:
static MyObject* _instance;
}
MyObject.cpp
MyObject* MyObject::_instance = 0;
MyObject* MyObject::Instance() {
if (_instance != 0) { //line 1
return _instance;
}
static ThreadMutex _instanceLock; //line 2
_instanceLock.Acquire(); //line 3
if (_instance == 0) {
_instance = new MyObject();
}
_instanceLock.Release();
return _instance;
}
MyObject will get accessed during application starting up (by two static object constructor) from two threads (yes the application has two threads even before main is started, one is main thread, another thread is created by a static object constructor). About 1 of 50 times, the application will crash at MyMutex::Lock() because "this=0x00000000"
When I debug on Visual Studio .Net 2005, it seemed to me what happened is the following in the order:
1. Thread 1 enters Instance() method at Line 1
2. Thread 1 proceeds to Line 2 because _instance =0, and Thread1 will initialize static object _instanceLock
3. Before _instanceLock is fullly constructed by Thread 1, Thread 1 is preempted by Thread 2
4. Thread 2 enters Instance() method at Line 1
5. Thread 2 proceeds to Line 3 because _instance =0 and static object _instanceLock is considered to be initialized at this time (decided by some sort complier flag )
6. Thread2 calls _instanceLock.Acquire(), which calls _lock->Lock(), but _lock is null at this time, since _instanceLock hasn't been fully constructed.
7. Application crashes
I think this can explain why this crashes happens occasionally.
I try to fix this by changing the function scope static _instnaceLock to class scope static, but found _instanceLock is still null when the first thread is trying to call _instanceLock.Acquire() and which of course crashes the application. This is understandable since we don't know the order of static objects get initialized during application starting up.
My another try is to use MyMutex directly in the Instance() method, which decreases the chances that threads get preempted during the construction of the _instanceLock object. So far I haven't seen crash yet with this change. But I think it's still not totally safe.
Could anyone tell me if my understanding about this crash is correct And is there any good approach to solve this problem
Thanks a lot!