多线程单例设计
普通的单例模式
class MyCas{
private:
MyCas(){}
static MyCas* m_instance;
public:
static MyCas *GetInstance()
{
if(m_instance == NULL)
{
m_instance = new MyCas();
static CGarhuishou cl;
}
return m_instance;
}
//内存回收类
class CGarhuishou
{
~CGarhuishou()
{
if(MyCas::m_instance)
{
delete MyCas::m_instance;
MyCas::m_instance = NULL;
}
}
}
}
问题:多个线程同时调用GetInstance()会有冲突。
解决方式:
//使用互斥量
std::mutex g_mutex;
class MyCas{
private:
MyCas(){}
static MyCas* m_instance;
public:
static MyCas *GetInstance()
{
std::unique_lock<std::mutex> res_mutex(g_mutex);
if(m_instance == NULL)
{
m_instance = new MyCas();
static CGarhuishou cl;
}
return m_instance;
}
//内存回收类
class CGarhuishou
{
~CGarhuishou()
{
if(MyCas::m_instance)
{
delete MyCas::m_instance;
MyCas::m_instance = NULL;
}
}
}
}
问题:效率太低,每次使用单例都需要获取互斥量。
解决方式:
std::mutex g_mutex;
class MyCas{
private:
MyCas(){}
static MyCas* m_instance;
public:
static MyCas *GetInstance()
{
if(m_instance == NULL)//双重检查(双重锁定)
{
std::unique_lock<std::mutex> res_mutex(g_mutex);
if(m_instance == NULL)
{
m_instance = new MyCas();
static CGarhuishou cl;
}
}
return m_instance;
}
//内存回收类
class CGarhuishou
{
~CGarhuishou()
{
if(MyCas::m_instance)
{
delete MyCas::m_instance;
MyCas::m_instance = NULL;
}
}
}
}
std::call_once
确保函数只被调用一次,具有互斥量能力,比互斥量消耗资源更少。与标记std::once_flag结合使用。
std::mutex g_mutex;
std::once_flag g_flag;
class MyCas{
static void CreateInstance()
{
m_instance = new MyCas();
static CGarhuishou cl;
}
private:
MyCas(){}
static MyCas* m_instance;
public:
static MyCas *GetInstance()
{
// if(m_instance == NULL)//双重检查
// {
// std::unique_lock<std::mutex> res_mutex(g_mutex);
// if(m_instance == NULL)
// {
// m_instance = new MyCas();
// static CGarhuishou cl;
// }
// }
std::call_once(g_flag,CreateInstance);//多个线程调用,后一个线程需要等待返回,此时g_flag类似互斥量的作用。
return m_instance;
}
//内存回收类
class CGarhuishou
{
~CGarhuishou()
{
if(MyCas::m_instance)
{
delete MyCas::m_instance;
MyCas::m_instance = NULL;
}
}
}
}
建议:最好在主线程创建单例。在子线程中直接使用单例对象。