剑指offer-02:设计一个单例模式的类

xiaoxiao2021-02-28  98

设计一个类,我们只能生成该类的一个实例。

分析:

只能生成一个实例的类,实际上是单例模式的类型。为防止用户生成新对象,将构造函数声明为私有或受保护生成一个对象,可以将其用静态成员函数来记录,指向这个对象的指针声明为静态变量,存放在静态存储区,把该类的对象用new来构造放在堆中 // vs 2015 #include "stdafx.h" #include <iostream> #include <mutex> #include <thread> using namespace std; class Singleton { private: // 该对象指针从属于该类 static Singleton *instance; Singleton() { cout << "generate!" << endl; }; Singleton(const Singleton &); public: static Singleton * GetInstance() { // 第一次创建时调用new;后面不再生成新对象 if (instance == nullptr) instance = new Singleton(); return instance; } }; Singleton* Singleton::instance = nullptr; int main() { // 第一次调用生成对象,OK Singleton::GetInstance(); // 后面再调用时将返回第一次生成的对象 Singleton::GetInstance(); return 0; }

程序在VS 2015中可运行。


问题:上述代码在单线程时工作正常。但在多线程下存在问题。如果两个线程同时运行到判断

if (instance == nullptr)

语句时,且instance还未被创建,则两个线程都会创建一个实例。这样就不满足单例模式的要求。

解决:多线程环境下加锁

mutex mux; class Singleton { // 其余代码相同 public: static Singleton * GetInstance() { // 加锁,其他线程等待 mux.lock(); if (instance == nullptr) instance = new Singleton(); // 解锁,其他线程进来发现已创建则返回 mux.unlock(); return instance; } }; Singleton* Singleton::instance = nullptr;

其实还有问题:每次想获取这个对象时,调用GetInstance函数都会试图上锁,造成效率不高。可以这样,由于每个时刻只有一个线程能得到锁,则每次先判断是否已创建,然后再加锁处理。

假设两个线程同时访问判断句,且此时并未创建,则两者竞争锁,有一个上锁进去创建对象然后退出。另一个得到锁进去发现已创建则退出。当后面再访问对象时,先判断是否创建,这时已创建则不会搞锁。

mutex mux; class Singleton { private: static Singleton *instance; Singleton() { cout << "generate!" << endl; }; Singleton(const Singleton &); public: static Singleton * GetInstance() { // 先判断是否已创建 // 没有再考虑上锁 if (instance == nullptr) { mux.lock(); if (instance == nullptr) instance = new Singleton(); mux.unlock(); } return instance; } }; Singleton* Singleton::instance = nullptr;
转载请注明原文地址: https://www.6miu.com/read-19694.html

最新回复(0)