单例模式

Posted on 2023-04-01 20:37  lyc2002  阅读(13)  评论(0编辑  收藏  举报

单例模式

在全局范围中,某个类的对象只有一个,通过这个唯一的实例向其他模块提供数据的全局访问。

需要:

  • 默认构造函数私有化
    • 因为使用者在类外部无法创建类对象,故在类内创建静态对象通过类名来访问
    • 在类中只有静态成员函数才能访问静态成员变量,故提供一个静态成员函数提供该静态对象
  • 拷贝构造函数私有化或禁用
  • 拷贝复制运算符私有化或禁用

饿汉模式

在类加载时立即实例化,无线程安全问题

class TaskQueue {
public:
    TaskQueue(const TaskQueue &t) = delete;
    TaskQueue &operator=(const TaskQueue &t) = delete;
    
    static TaskQueue *get_instance() { return m_taskQ; }
private:
    TaskQueue() = default;
    
    static TaskQueue *m_taskQ;
};

TaskQueue *TaskQueue::m_taskQ = new TaskQueue;

int main()
{
    TaskQueue *t = TaskQueue::get_instance();
}

懒汉模式

在加载时不创建唯一实例,直到使用才创建,有线程安全问题

class TaskQueue {
public:
    TaskQueue(const TaskQueue &t) = delete;
    TaskQueue &operator=(const TaskQueue &t) = delete;
    
    static TaskQueue *get_instance() {
        if (m_taskQ == nullptr) {
            m_taskQ = new TaskQueue;
        }
        return m_taskQ;
    }
private:
    TaskQueue() = default;
    
    static TaskQueue *m_taskQ;
};

TaskQueue *TaskQueue::m_taskQ = nullptr;

线程安全问题处理

双重检查锁定

class TaskQueue {
public:
    TaskQueue(const TaskQueue &t) = delete;
    TaskQueue &operator=(const TaskQueue &t) = delete;
    
    static TaskQueue *get_instance() {
        if (m_taskQ == nullptr) {
            m_mutex.lock();
        	if (m_taskQ == nullptr) {
            	m_taskQ = new TaskQueue;
        	}
        	m_mutex.unlock();
        }
        return m_taskQ;
    }
private:
    TaskQueue() = default;
    
    static TaskQueue *m_taskQ;
    static mutex m_mutex;
};

TaskQueue *TaskQueue::m_taskQ = nullptr;
mutex TaskQueue::m_mutex;

上述代码在 m_taskQ = new TaskQueue 处由于机器指令重排加上恰好时间片结束,仍然会出现线程安全问题

class TaskQueue {
public:
    TaskQueue(const TaskQueue &t) = delete;
    TaskQueue &operator=(const TaskQueue &t) = delete;
    
    static TaskQueue *get_instance() {
        TaskQueue *queue = m_taskQ.load();
        if (queue == nullptr) {
            lock_gard<mutex> locker(m_mutex);
            queue = m_taskQ.load();
            if (queue == nullptr) {
                queue = new TaskQueue;
                m_taskQ.store(queue);
            }
        }
        return queue;
    }
private:
    TaskQueue() = default;
    
    static atomic<TaskQueue *> m_taskQ;
    static mutex m_mutex;
};

atomic<TaskQueue *> TaskQueue::m_taskQ;
mutex TaskQueue::m_mutex;

静态局部对象

class TaskQueue {
public:
    TaskQueue(const TaskQueue &t) = delete;
    TaskQueue &operator=(const TaskQueue &t) = delete;
    
    static TaskQueue *get_instance() {
        static TaskQueue taskQ;
        return &taskQ;
    }
private:
    TaskQueue() = default;
};