单例模式

单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。有很多地方需要这样的功能模块,如系统的日志输出,GUI应用必须是单鼠标,MODEM的联接需要一条且只需要一条电话线,操作系统只能有一个窗口管理器,一台PC连一个键盘。显然单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。

#include<iostream>
#include <afxmt.h>
using namespace std;

class Lock
{
private:
    CCriticalSection m_cs;
public:
    Lock(CCriticalSection  cs) : m_cs(cs)
    {
        m_cs.Lock();
    }
    ~Lock()
    {
        m_cs.Unlock();
    }
};

class Singleton
{
private:
    Singleton();
    Singleton(const Singleton &);
    Singleton& operator = (const Singleton &);
    static Singleton *_pInstance;

public:
    static Singleton *Instantialize();
    static CCriticalSection cs;
};

Singleton* Singleton::_pInstance = NULL;

Singleton* Singleton::Instantialize()
{
    if (_pInstance == NULL)
    {   //double check 
        Lock lock(cs);   //用lock实现线程安全,用资源管理类,实现异常安全。 使用资源管理类,在抛出异常的时候,资源管理类对象会被析构,析构总是发生的无论是因为异常抛出还是语句块结束。 
        if (_pInstance == NULL)
        {
            _pInstance = new Singleton();
        }
    }
    return _pInstance;
}

int main()
{
    Singleton::Instantialize();
    getchar();
    return 0;
}

1.静态实例,带有static关键字的属性在每一个类中都是唯一的。静态的成员函数只能访问静态的成员变量。
2.限制客户端随意创造实例,即私有化构造方法,此为保证单例的最重要的一步。
3.给一个公共的获取实例的静态方法,注意,是静态的方法,因为这个方法是在我们未获取到实例的时候就要提供给客户端调用的,所以如果是非静态的话,那就变成一个矛盾体了,因为非静态的方法必须要拥有实例才可以调用。
4、值得注意的是再次判断了_pInstance是否为null,解释下为什么要这样做。
假设我们去掉第二次是否为null的判断,有这样一种情况,假设A线程和B线程都在同步块外面判断了_pInstance为null,结果A线程首先获得了线程锁,进入了同步块,然后A线程会创造一个实例,此时_pInstance 已经被赋予了实例,A线程退出同步块,直接返回了第一个创造的实例,此时B线程获得线程锁,也进入同步块,此时A线程其实已经创造好了实例,B线程正常情况应该直接返回的,但是因为同步块里没有判断是否为null,直接就是一条创建实例的语句,所以B线程也会创造一个实例返回,此时就造成创造了多个实例的情况。
5、类CCriticalSection的对象表示一个”临界区”,它是一个用于同步的对象,同一时刻只允许一个线程存取资源或代码区。

你可能感兴趣的:(单例模式,线程安全,异常安全)