C++设计模式之单例模式

C++设计模式之单例模式

一、使用情景

在很多环境下,我们需要保证某些特殊对象在整个系统中的唯一性。windows的资源管理器就是一个很好的例子。无论我们点击多少次“启动任务管理器”都只弹出来一个任务管理器窗口。因为如果弹出多个窗口,而这些窗口的内容都一模一样,全部都是重复的对象,那是没有意义的,而且还会浪费系统资源。而单例模式就能很好地在这种情景之下应用。

二、实现

单例模式在类外无法直接创建对象,只能通过类本身来创建对象。单例模式具有两个特点:
+ 该类只有一个对象
+ 类必须自行创建这个实例对象

单例模式的结构如下图所示:

三、代码分析

下面给出单例模式的实例代码

#include <iostream>
#include <string>
using std::string;

class Singleton : boost::noncopyable{
private:
  string Name;
  static Singleton *instance;
  //保证外部无法创建实例
  Singleton (const string& name) { Name = name;}
  ~Singleton(){}
public:
  void whoAmI(){std::cout << "Name = " << Name << std::endl;}
  static Singleton *getInstance(string name){
    if (instance == NULL)
        instance = new Singleton(name);
    return instance;
  }
};

int main(void){
  Singleton *instance1 = Singleton::getInstance("instance1");
  Singleton *instance2 = Singleton::getInstance("instance2");
  Singleton *instance3 = Singleton::getInstance("instance3");

  instance1.whoAmI();
  instance2.whoAmI();
  instance3.whoAmI();

  return 0;
}

运行结果为:  
Name = instance1  
Name = instance1  
Name = instance1

这里至关重要的技巧是将构造函数声明为私有,类的构造只能通过一个静态成员函数getInstance来构造,而该构造函数控制构造行为,达到构造唯一实例的目的

四、多线程环境下的单例模式

从上述代码中可以看到,我们利用一句if (instance == NULL)来控制实例的创建,在多线程环境中,假设A线程正在创建实例的时候,B进程又调用了一个getInstance,此时if (instance == NULL)的判断依旧成立,从而创建又一个实例。在下面的测试中运行

int main(void){

  Singleton *instance1, *instance2, *instance3;
  pthread_t p1, p2, p3;
  pthread_create(&p1, NULL, getSingleton1, &instance1);
  pthread_create(&p2, NULL, getSingleton2, &instance2);
  pthread_create(&p3, NULL, getSingleton3, &instance3);

  pthread_join(p1, NULL);
  pthread_join(p2, NULL);
  pthread_join(p3, NULL);


  instance1->whoAmI();
  instance2->whoAmI();
  instance3->whoAmI();

  return 0;
}

运行结果为:
Name = instance1
Name = instance2
Name = instance3

所以单例模式必须要考虑线程同步,以下给出多线程版本

#include <iostream>
#include <string>
#include <pthread.h>

using std::string;

class Lock {
private:
  pthread_mutex_t lock;
public:
  Lock(){
    pthread_mutex_init(&lock, NULL);
  }
  int getLock(){return pthread_mutex_lock(&lock);}
  int unLock(){return pthread_mutex_unlock(&lock);}
  virtual ~Lock(){ pthread_mutex_unlock(&lock);}
};

class Singleton :  boost::nocopyable {
private:
  string Name;
  static Singleton *instance;
  //保证外部无法创建实例
  ~Singleton(){}
  Singleton (const string& name) { Name = name;}
public:
  void whoAmI(){std::cout << "Name = " << Name << std::endl;}
  static Singleton *getInstance(string name){
    Lock lock;
    lock.getLock();
    if (instance == NULL)
        instance = new Singleton(name);
    lock.unLock();
    return instance;
  }
};

运行结果为:
Name = instance1
Name = instance1
Name = instance1

注:关于LINUX线程的文章请看我的另一篇博客《深入理解linux线程》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值