单例类设计模式
软件设计模式(Design pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
而单例类设计模式就是一种常用的软件设计模式。这种设计模式确保类仅生成一个对象。并提供一个全局的访问点来访问该对象。常用于配置文件的读取、数据库连接池、线程池等场景。
在单例类设计模式中,类的构造函数通常是private的,并提供一个静态的函数返回该类的唯一实例对象。当第一次调用该该静态函数时,就会创建该类的唯一实例对象,当此后再调用该静态函数时,则返回已经创建的实例对象,不再创建新的实例对象。
#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
mutex mymutex;//全局互斥量
class Singleton
{
public:
static Singleton* getInstance()
{
if (instance==NULL) //双重判断,提高效率
{
unique_lock<std::mutex> myunmutex(mymutex);//防止多线程同时执行导致出现多个实例对象
if (instance == NULL)
{
instance = new Singleton();
static CGarclear c1;
}
}
return instance;
}
class CGarclear//利用其析构释放new的Singleton对象内存
{
public:
~CGarclear()
{
if (Singleton::instance)
{
delete Singleton::instance;
Singleton::instance = NULL;
}
}
};
private:
static Singleton* instance;
Singleton() {}//私有构造函数
};
Singleton* Singleton::instance =NULL;//初始化静态成员
void mythread()//线程入口函数
{
Singleton* p =Singleton::getInstance();
}
int main()
{
thread mytobj1(mythread);
thread mytobj2(mythread);
mytobj1.join();
mytobj2.join();
}
使用单例类设计模式时,最后在主线程main函数中线程执行前实例单例类对象。否则就有可能造成多个线程一起执行getInstance()函数,当某一线程判断instance为空但还未new时,跳转到另一线程同样判断instance为空,这样执行多次new造成出现多个实例对象。因此如果有在自主线程执行后使用单例类的需求,就应该使用互斥量防止以上情况的发生。同时为了避免多次使用互斥量导致代码效率下降,可以使用双重判断,确保仅在instance为空时才调用互斥量。
call_once
std::call_once 是 C++11 引入的一个函数,用于确保某个操作只执行一次,即使在多线程环境中被多次调用。因此call_once对于单例类的实现十分有用。
std::call_once需要一个 std::once_flag(实际上是一个结构) 对象作为参数,该对象用于跟踪函数是否已经执行过。当 std::call_once 被调用时,它会检查 std::once_flag 的状态。如果函数尚未执行,std::call_once就会执行提供的可调用对象(通常是一个函数或 lambda 表达式),并将 std::once_flag设置为已执行状态。如果函数已经执行过,std::call_once`则不会再次执行它。
使用call_once 改造上面代码:
#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
mutex mymutex;//全局互斥量
once_flag g_flag;
class Singleton
{
private:
static void createInstance()
{
instance = new Singleton();
static CGarclear cl;
}
public:
static Singleton* getInstance()
{
call_once(g_flag,createInstance );//确保仅执行一次createInstance
return instance;
}
class CGarclear//利用其析构释放new的Singleton对象内存
{
public:
~CGarclear()
{
if (Singleton::instance)
{
delete Singleton::instance;
Singleton::instance = NULL;
}
}
};
private:
static Singleton* instance;
Singleton() {}//私有构造函数
};
Singleton* Singleton::instance = NULL;//初始化静态成员
void mythread()//线程入口函数
{
Singleton* p = Singleton::getInstance();
}
int main()
{
thread mytobj1(mythread);
thread mytobj2(mythread);
mytobj1.join();
mytobj2.join();
}