[学习][笔记]设计模式(基于C/C++实现)<一>单例模式

简介: [学习][笔记]设计模式(基于C/C++实现)<一>单例模式

前言

单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

使用场景

1.程序运行过程,都是只需要一个对象的情况,如全局配置Configure

基本思路

  1. 构造函数声明为private或protect防止被外部函数实例化。
  2. 提供一个全局的静态方法(全局访问点)。
  3. 内部保存一个private static的类指针保存唯一的实例,实例的动作由一个public的类方法代劳,该方法也返回单例类唯一的实例。

例1.0

#include <iostream>
using namespace std;
class SingletonBase
{
protected:
    SingletonBase(){
        cout<<"SingletonBase created"<<endl;
    };
    ~SingletonBase(){
        cout<<"SingletonBase destoryed"<<endl;
    };
private:
    static SingletonBase* ptr;
public:
    static SingletonBase* GetInstance(){
        if (ptr== NULL){
            ptr = new  SingletonBase();
        }
        return ptr;
    }
};
SingletonBase* SingletonBase::ptr = NULL;

如果不考虑线程安全这样是可以的。

解释线程安全:

线程安全,指多线程并发调用时,对同一信号量进行操作时,存在幻读,脏读等线程问题。

例如:

线程A 调用GetInstance(),线程B

也同时调用GetInstance(),同一时刻,由于没有加锁,导致从内存读入的数据都是ptr=NULL,导致同一时间都会new一个,极大浪费了空间,且线程A,B最后操作的对象极有可能不是一个对象。

所以考虑线程安全这样是不行的。所以有了以下两种

1.懒汉式

顾名思义:懒人,第一次用到的时候才会想到去创建,跟懒加载概念类似。以时间换空间,用到的时候,会需要时间去创建实体,以减少不用的时候的堆空间。

例1.0就是最基本的懒汉式。

为了解决线程安全问题,我们选择一种方法

加锁

例1.1

#include <iostream>
#include <mutex>
using namespace std;
/**
 * use lock
 */
class SingletonLazy1
{
protected:
    SingletonLazy1(){
        cout<<"SingletonBase created"<<endl;
    };
    ~SingletonLazy1(){
        cout<<"SingletonBase destoryed"<<endl;
    };
private:
    static SingletonLazy1* ptr;
public:
    static mutex singleton_lock;
    static SingletonLazy1* GetInstance(){
        singleton_lock.lock();
        if (ptr== NULL){
            ptr = new  SingletonLazy1();
        }
        singleton_lock.unlock();
        return ptr;
    }
};
mutex SingletonLazy1::singleton_lock;
SingletonLazy1* SingletonLazy1::ptr=NULL;

同理也可以使用智能指针 lock_guard,shared_lock,unique_lock

2.饿汉式

顾名思义:饿汉,饥不择食,要吃现成的,必须类一加载,就创建,必须及时。以空间换时间,省去用到时加载的时间。

优点:

  • 不需要加锁
  • 提前创建好实例对象

缺点:

  • 空间换时间,如果不需要实例,也会默认创建实例

例1.2

#include <iostream>
#include <mutex>
using namespace std;
/**
 * hungry mode
 */
class SingletonHungry
{
protected:
    SingletonHungry(){
        cout<<"SingletonBase created"<<endl;
    };
    ~SingletonHungry(){
        cout<<"SingletonBase destoryed"<<endl;
    };
private:
    static SingletonHungry* ptr;
public:
    static SingletonHungry* GetInstance(){
       return ptr;
    }
};
SingletonHungry* SingletonHungry::ptr=new SingletonHungry;
关于饿汉式的线程安全问题

饿汉式内 变量线程安全我持怀疑态度

实例 多线程情况下使用单例

问题:开三个线程,使之变量A = 0,累加到100,顺序执行?

/*
 *
 * 问题:开三个线程,使之变量A = 0,累加到100,顺序执行?
 *
 */
//void ThreadFunc1(){
//    while(1){
//        if(SingletonBase::GetInstance()->counter >100){
//            return;
//        }
//        cout<<(SingletonBase::GetInstance()->counter++)<<endl;
//    }
//}
void ThreadFunc2(){
    while(1){
        MyLock.lock();
        if(SingletonLazy1::GetInstance()->counter >100){
            MyLock.unlock();
            return;
        }
        cout<<(SingletonLazy1::GetInstance()->counter++)<<endl;
        MyLock.unlock();
    }
}
void ThreadFunc3(){
    while(1){
        MyLock.lock();
        if(SingletonHungry::GetInstance()->counter >100){
            MyLock.unlock();
            return;
        }
        cout<<(SingletonHungry::GetInstance()->counter++)<<endl;
        MyLock.unlock();
    }
}
int main()
{
   use Base
//    thread th1(ThreadFunc1);
//    thread th2(ThreadFunc1);
//    thread th3(ThreadFunc1);
//    th1.join();
//    th2.join();
//    th3.join();
 use Lazy
//    thread th1(ThreadFunc2);
//    thread th2(ThreadFunc2);
//    thread th3(ThreadFunc2);
//    th1.join();
//    th2.join();
//    th3.join();
    thread th1(ThreadFunc3);
    thread th2(ThreadFunc3);
    thread th3(ThreadFunc3);
    th1.join();
    th2.join();
    th3.join();
    return 0;
}

补充一点:

Qt项目可以直接使用std::thread

No-Qt项目中,需要CONFIG += thread

总结

demo地址

相关文章
|
8天前
|
C++
c++的学习之路:27、红黑树
c++的学习之路:27、红黑树
28 4
|
8天前
|
Java C++
C++的学习之路:21、继承(2)
C++的学习之路:21、继承(2)
16 0
|
8天前
|
编译器 C语言 C++
c++的学习之路:19、模板
c++的学习之路:19、模板
30 0
|
8天前
|
设计模式 存储 Android开发
c++的学习之路:18、容器适配器与反向迭代器
c++的学习之路:18、容器适配器与反向迭代器
19 0
|
3天前
|
设计模式 安全 Java
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
|
8天前
|
存储 C++ 容器
c++的学习之路:26、AVL树
c++的学习之路:26、AVL树
26 0
|
8天前
|
编译器 C++
c++的学习之路:22、多态(1)
c++的学习之路:22、多态(1)
20 0
c++的学习之路:22、多态(1)
|
8天前
|
安全 编译器 程序员
c++的学习之路:20、继承(1)
c++的学习之路:20、继承(1)
27 0
|
1天前
|
编译器 C语言 C++
【C++入门学习指南】:函数重载提升代码清晰度与灵活性
【C++入门学习指南】:函数重载提升代码清晰度与灵活性
9 0
|
5天前
|
C++
C++虚函数学习笔记
C++虚函数学习笔记
10 0