单例模式:全局范围内,某个实例有且仅有一个通过这个某一实例向其他模块提供数据的全局访问。
单例模式–饿汉模式
#include <iostream>
using namespace std;
//饿汉模式->定义类的时候创建单例对象
//定义单例模式的任务队列
class TaskQueue {
public:
TaskQueue(const TaskQueue & t) = delete;
TaskQueue & operator = (const TaskQueue& t) = delete;
//静态公共函数
static TaskQueue* getInstance()
{
return m_taskQ;
}
void print()
{
cout << "单例对象的一个成员函数" << endl;
}
private:
TaskQueue() = default;
// TaskQueue(const TaskQueue& t) = default;
// TaskQueue& operator = (const TaskQueue& t) = default;
//只能通过类名访问静态属性或方法
static TaskQueue* m_taskQ;
//静态成员变量不能在类中初始化
};
//静态成员变量只能在类外初始化
TaskQueue* TaskQueue::m_taskQ = new TaskQueue;
//TaskQueue* TaskQueue::m_taskQ = nullPtr;
int main()
{
TaskQueue* taskQ = TaskQueue::getInstance();//得到唯一单例对象
taskQ->print();
return 0;
}
单例模式–懒汉模式
#include <iostream>
#include <mutex>
using namespace std;
//懒汉模式->什么时候使用这个单例,在使用时侯再去创建
//懒汉模式比饿汉模式更胜内存空间,但饿汉模式没有线程安全问题
//定义单例模式的任务队列
class TaskQueue {
public:
TaskQueue(const TaskQueue& t) = delete;
TaskQueue& operator = (const TaskQueue& t) = delete;
//静态公共函数
static TaskQueue* getInstance()
{
//为了提高效率在加双重检查锁定
if (m_taskQ == nullptr)
{
//懒汉模式防止线程问题需在函数中加入互斥锁;
m_mutex.lock();
if(m_taskQ == nullptr)
{
m_taskQ = new TaskQueue;
}
m_mutex.unlock();
}
return m_taskQ;
}
void print()
{
cout << "单例对象的一个成员函数" << endl;
}
private:
TaskQueue() = default;
// TaskQueue(const TaskQueue& t) = default;
// TaskQueue& operator = (const TaskQueue& t) = default;
//只能通过类名访问静态属性或方法
static TaskQueue* m_taskQ;
//互斥锁
static mutex m_mutex;
//静态成员变量不能在类中初始化
};
//静态成员变量只能在类外初始化
TaskQueue* TaskQueue::m_taskQ = nullptr;
mutex TaskQueue::m_mutex;
int main()
{
TaskQueue* taskQ = TaskQueue::getInstance();//得到唯一单例对象
taskQ->print();
return 0;
}
双重检查锁定问题:第一个线程new完m_maskQ还没有写入内存就被第二个线程使用。
C++11引入原子变量atomic的store()方法来存实例对象
#include <iostream>
#include <mutex>
#include <atomic>
using namespace std;
//懒汉模式->什么时候使用这个单例,在使用时侯再去创建
//懒汉模式比饿汉模式更胜内存空间,但饿汉模式没有线程安全问题
//定义单例模式的任务队列
class TaskQueue {
public:
TaskQueue(const TaskQueue& t) = delete;
TaskQueue& operator = (const TaskQueue& t) = delete;
//静态公共函数
static TaskQueue* getInstance()
{
//从原子变量中取出
TaskQueue* task = m_taskQ.load();
//为了提高效率在加双重检查锁定
if (task == nullptr)
{
//懒汉模式防止线程问题需在函数中加入互斥锁;
m_mutex.lock();
task = m_taskQ.load();
if(m_taskQ == nullptr)
{
task = new TaskQueue;
m_taskQ.store(task);
}
m_mutex.unlock();
}
return task;
}
void print()
{
cout << "单例对象的一个成员函数" << endl;
}
private:
TaskQueue() = default;
// TaskQueue(const TaskQueue& t) = default;
// TaskQueue& operator = (const TaskQueue& t) = default;
//只能通过类名访问静态属性或方法
//static TaskQueue* m_taskQ;
//互斥锁
static mutex m_mutex;
//原子变量定义任务对列指针类型,指针为空;
static atomic<TaskQueue*> m_taskQ;
//静态成员变量不能在类中初始化
};
//静态成员变量只能在类外初始化
atomic<TaskQueue*> TaskQueue::m_taskQ;
mutex TaskQueue::m_mutex;
int main()
{
TaskQueue* taskQ = TaskQueue::getInstance();//得到唯一单例对象
taskQ->print();
return 0;
}
使用静态局部对象解决线程安全问题(要求支持C++11)
class TaskQueue {
public:
TaskQueue(const TaskQueue& t) = delete;
TaskQueue& operator = (const TaskQueue& t) = delete;
//静态公共函数
static TaskQueue* getInstance()
{
static TaskQueue task;
return &task;
}
void print()
{
cout << "单例对象的一个成员函数" << endl;
}
private:
TaskQueue() = default;
// TaskQueue(const TaskQueue& t) = default;
// TaskQueue& operator = (const TaskQueue& t) = default;
};