C++ 单例线程安全一致性和自动回收及模板泛型实现

实现单例不难,最简单的方式如下:

class SingleTon
{
  public:
    static SingleTon & GetInstance()
    {
        static SingleTon;
        return SingleTon;
    }
protected:
    SingleTon()
    {
    }
    SingleTon(const SingleTon &){}
};

再或者返回指针类型,new出单例对象,此时就应该考虑线程安全性问题了,常有的方式是doule check ,当GetInstance 方法中检测到instance指针为空时,需要加锁,然后再次判断是否为空,此时还为空再创建instance对象,避免不检查出现和其他线程重复创建这个类的对象,完整代码如下:

SingleTon.h

//
//  SingleTon.hpp
//  CodeTest
//
//  Created by xiangzhenwei on 2019/4/20.
//  Copyright © 2019年 xiangzhenwei. All rights reserved.
//

#ifndef SingleTon_hpp
#define SingleTon_hpp

#include <stdio.h>
#include <pthread.h>

template <typename T>
class Singleton
{
public:
   static T * GetInstance();
protected:
    Singleton()
    {
        printf("Singleton constcut called...\n");
        
    };
    ~ Singleton()
    {
        printf("Singleton desconstcut called...\n");
    };
protected:
    class GC
    {
    public:
        GC()
        {
            printf("GC constcut Begin call!\n");
        }
        ~GC()
        {
            printf("GC Desctuct begin call...\n");
            if(m_instance)
            {
                delete m_instance;
            }
        }
    };
protected:
    static GC m_gc;
private:
    Singleton(const Singleton &) {}
    Singleton & operator= (const Singleton &){}
    static T * m_instance;
    static pthread_mutex_t m_metux;
};

//保护类型的单例构造函数,友元访问
#define SPECAIL_SINGLETON(classType)  friend class Singleton<classType>;

//单例模板类特化,垃圾回收期指定
#define SPECAIL_SINGLETON_GC(T) template Singleton<T>::Singleton<T>::GC Singleton<T>::Singleton<T>::m_gc;

#define IMPL_SINGLE_TON
#include "SingleTon.cpp"

#endif /* SingleTon_hpp */

SingleTon.cpp

//
//  SingleTon.cpp
//  CodeTest
//
//  Created by xiangzhenwei on 2019/4/20.
//  Copyright © 2019年 xiangzhenwei. All rights reserved.
//

#ifdef IMPL_SINGLE_TON

template <typename T>
T * Singleton<T>::m_instance = NULL;

template <typename T>
pthread_mutex_t Singleton<T>::m_metux = PTHREAD_MUTEX_INITIALIZER;

template <typename T>
typename Singleton<T>::GC Singleton<T>::m_gc;

template <typename T>
T * Singleton<T>::GetInstance()
{
    if(m_instance == NULL)
    {
        pthread_mutex_lock(&m_metux);
        if(m_instance == NULL)
        {
            m_instance = new T();
        }
        pthread_mutex_unlock(&m_metux);
    }
    return m_instance;
}
#endif

以上使用方式使用了模板函数,并实现了单例的垃圾自动回收

#define SPECAIL_SINGLETON_GC(T) template Singleton<T>::Singleton<T>::GC Singleton<T>::Singleton<T>::m_gc;

上面这段代码是对模板单例方法垃圾回收期静态定义的一个宏实现,例如定义了一个UserManager单例,则需要在UserManager实现的cpp加上一行代码,如下,才能确保垃圾回收期静态对象在程序启动的时候被构造,程序退出的时候被析构,调用单例的释放函数。

SPECAIL_SINGLETON_GC(UserManager)

定义了以上的模板类,下面来特化一下单例模板类:

//
//  main.cpp
//  CodeTest
//
//  Created by xiangzhenwei on 2019/4/20.
//  Copyright © 2019年 xiangzhenwei. All rights reserved.
//

#include <iostream>
#include "SingleTon.h"
#include <string>
#include <vector>

class ShapeMgr
{
    SPECAIL_SINGLETON(ShapeMgr)
private:
    ShapeMgr()
    {
        printf("ShapeMgr constuct...\n");
    }
    ShapeMgr(const ShapeMgr &) {}
public:
    ~ShapeMgr()
    {
        printf("ShapeMgr destruct\n");
    }
    void SayType()
    {
        printf("ShapeMgr SayType called,this->ptr=%p\n",this);
    }
};

class PersonMgr
{
     SPECAIL_SINGLETON(PersonMgr)
private:
    PersonMgr()
    {
        printf("PersonMgr constuct...\n");
    }
    PersonMgr(const PersonMgr &) {}
public:
    ~PersonMgr()
    {
        printf("PersonMgr destruct\n");
    }
    void SayType()
    {
        printf("PersonMgr SayType called,this->ptr=%p\n",this);
    }
};

SPECAIL_SINGLETON_GC(ShapeMgr)
SPECAIL_SINGLETON_GC(PersonMgr)
SPECAIL_SINGLETON_GC(int)
SPECAIL_SINGLETON_GC(double)
SPECAIL_SINGLETON_GC(float)
SPECAIL_SINGLETON_GC(std::string)
SPECAIL_SINGLETON_GC(std::vector<int>)

int main(int argc, const char * argv[]) {
    // insert code here...
    std::cout << "Hello, World!\n";
    
    ShapeMgr *  p1 = Singleton<ShapeMgr>::GetInstance();
    if (p1 == NULL) {
        printf("Bad instance returned\n");
        return -1;
    }
    p1->SayType();
    
    ShapeMgr *  p2 = Singleton<ShapeMgr>::GetInstance();
    p2->SayType();
    
    PersonMgr *  p3 = Singleton<PersonMgr>::GetInstance();
    if (p3 == NULL) {
        printf("Bad instance returned\n");
        return -1;
    }
    p3->SayType();
    
    PersonMgr * p4 = Singleton<PersonMgr>::GetInstance();
    p4->SayType();
    
    int * pInt = Singleton<int>::GetInstance();
    *pInt = 121231;
    int * pb = Singleton<int>::GetInstance();
    
    std::vector<int> * pv = Singleton<std::vector<int> >::GetInstance();
    pv->push_back(1);
    pv->push_back(2);
    std::vector<int> * pv23 = Singleton<std::vector<int> >::GetInstance();
    
    return 0;
}

在ShapeMgr特化时,需要加一行友元申明代码:

 SPECAIL_SINGLETON(ShapeMgr)

保证GetInstance方法能够调用ShapeMgr的构造函数,因为单例类的构造函数我们通常是定义为保护或者私有的。

下面是以上代码编译运行的截图:

以上是个人思考和实践,当然GetInstance 中double check也不是唯一方法,只是也可以使用其他方式,例如:

int pthread_once(pthread_once_t *, void (* _Nonnull)(void)); 实现了一个进程只调用一次的方法,pthread_once传入我们单例初始化函数,也是可以的,大致代码如下:

SingleTon * SingleTon::m_instance = NULL;
pthread_once_t SingleTon::once_control = PTHREAD_ONCE_INIT;

void init_singleton()
{
    if(m_instance ==NULL)
    {
        m_instance = new Singleton();
    }
}

SingleTon * GetInstance()
{
    if(m_instance == NULL)
    {
        pthread_once(&once_control,init_singleton);
    }
    return m_instance;
}

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值