鱼C论坛

 找回密码
 立即注册
查看: 1424|回复: 1

[技术交流] 写了一个简单的单例模式分享

[复制链接]
发表于 2018-10-25 21:06:04 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
/**
一个简单的懒汉式单例模式出现的问题及解决方案
*/

#include <iostream>
#include <thread>
#include <mutex>

#define THREAD_NUM 10

using namespace std;

class Singleton
{
public:
        //12.此处加一个垃圾清理类就可以实现程序退出前调用Singleton的析构函数了
        class Garbo
        {
        public:
                ~Garbo()
                {
                        if (nullptr != mInstance)
                        {
                                delete mInstance;
                        }
                }
        };


        //3.为了能够在类外使用对象,所以需要提供一个成员函数用来使对象能够
        //在类外使用,由于其他函数不能够直接用类名访问成员函数,而单例又不能在类外
        //产生对象来调用类的相关成员函数,所以这里用静态成员函数以供类外访问唯一实例
        static Singleton* getInstance()
        {
                //4.由于懒汉式是使用的时候产生对象,所以需要先new一个对象,由于只能使
                //其产生一次,所以这里需要引入第一重判断

                //7.由于多线程问题,这里考虑加锁,加锁后能产生单个实例对象了,但是引入
                //频繁加锁和解锁的开销,导致程序执行效率不够理想

                //9.为了不让每个线程执行时都进入加锁状态,这里需要引入双重判定,使其只有
                //进入加锁状态,减少系统开销

                //10.要让对象在进程结束前执行析构函数又需要怎么弄?
                //可以引入一个垃圾清理类Garbo
                if (nullptr == mInstance)
                {
                        //mInstanceMutex.lock();
                        lock_guard<mutex> guard(mInstanceMutex);

                        //13.问题又出现了,如果在加锁和解锁这段程序中间需要进行错误处理,
                        //抛出异常,程序就会出现死锁,怎么解决,思路是利用局部变量的作用域
                        //在{},也就是在括号结束对象会调用其析构函数,将锁换成门卫类
                        if (nullptr == mInstance)
                        {
                                mInstance = new Singleton();
                                throw 1;
                        }

                        //mInstanceMutex.unlock();
                }
                return mInstance;
        }

private:
        //1.为了只能产生一个对象,所以不能让其能在类外产生对象,所以需要先私有化
        //其默认构造函数和默认拷贝构造函数,如果是C++11还需要将其移动构造函
        //数私有化
        Singleton()
        {
                cout << "Singleton Constructor!" << endl;
        }

        Singleton(const Singleton &singleton)
        {
                cout << "Singleton Copy Constructor!" << endl;
        }

        Singleton(const Singleton &&sigleton)
        {
                cout << "Singleton Move Constructor!" << endl;
        }

        ~Singleton()
        {
                cout << "Singleton Destructor!" << endl;
        }

        //2.由于类外不能产生对象,所以需要在类内构造一个类外全局能够访问的对象
        //(静态变量的生命周期可以胜任此需求);可以有两种方式,一种方式是直接在类
        //内定义一个对象,比较简单,另一种方式是在类内定义一个指针,此种情况下分
        //为懒汉式和饿汉式两种模式,由于懒汉式问题较多,故而这里只写懒汉式
        static Singleton *mInstance;

        //8.由于要加锁,先定义一个静态的互斥量
        static mutex mInstanceMutex;

        //11.定义Garbo类型的静态成员,由于进程结束会调用其析构函数,所以可以
        //实现在进程结束前释放掉单例对象
        static Garbo mGarbo;
};

//注意:*写在mInstance前Singleton后编译会产生链接错误,
Singleton *Singleton::mInstance = nullptr;
mutex Singleton::mInstanceMutex;
Singleton::Garbo Singleton::mGarbo;

void fun(int num)
{
        try
        {
                //cout << num << endl;
                //6.在每个线程中使用懒汉式产生出来的实例
                //这样在多线程中会产生多个实例,不符合单例模式,解决方式可以考虑加锁
                Singleton::getInstance();
        }
        catch (...)
        {
        }
}
int main()
{
        //5.创建多个线程来测试懒汉式单例模式的问题
        thread  *arr[THREAD_NUM] = { nullptr };
        for (int i = 0; i < THREAD_NUM; i++)
        {
                //new出所有线程
                arr[i] = new thread(fun, i);
        }

        for (int i = 0; i < THREAD_NUM; i++)
        {
                //等待所有线程结束,回收资源
                arr[i]->join();

        }

        for (int i = 0; i < THREAD_NUM; i++)
        {
                delete arr[i];
        }

        return 0;
}

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-25 21:17:52 | 显示全部楼层
有点看不懂,这里是学到c++哪里才能知道这些?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-10-3 12:38

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表