accessing the same static instance from two different threads
I have a singleton class A
: the creation of the instance is done in the main thread main()
, the class thread
will launch the mainThread()
that get the instance _instance
of class A
.
class A
{
public:
A() {}
static void setInstance()
{
if (!_instance)
{
_instance = new A();
}
}
static A* getInstance()
{
return _instance;
}
void bulk()
{
std::cout << "at A()" << std::endl;
}
static A* _instance;
};
A* A::_instance = 0;
class thread
{
public:
thread() {}
void threadMain()
{
// this is the thread main
A::getInstance()->bulk();
}
std::thread member1Thread()
{
return std::thread([=] { threadMain(); });
}
};
int main()
{
A::setInstance();
thread th;
std::thread tw1 = th.member1Thread();
A::getInstance()->bulk();
delete A::_instance;
return 0;
}
So _instance
is a shared resource ? how I unblock this situation. I tried to go through a global mutex
static A* getInstance()
{
mutex.lock();
return _instance;
}
void bulk()
{
std::cout << "at A()" << std::endl;
mutex.unlock();
}
does my code thread safe ?
Solution 1:
Your code is mostly thread safe. The tricks with the mutex work. However, you don't have guarantees that the new thread is finished by the time you delete the instance. You should join your thread before it to ensure it finished.
That said, this code wouldn't pass my code review. It's too unpredictable.
First of all, never call lock/unlock on mutexes. Use std::unique_lock instead. That way you'll never forget to unlock as it will do it for you. As such, the locking should actually happen outside of the methods, which is easier to understand.
Secondly, this is one of the few places where std::shared_ptr can make sense. You construct it once and pass the life time into the threads. However, you could as well put an instance on the stack, as you have control about the end of all threads.
Thirdly, singletons are evil.