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

单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。
GoF对单例模式的定义是:保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。

在应用系统开发中,我们常常有以下需求:
- 在多个线程之间,比如初始化一次socket资源;比如servlet环境,共享同一个资源或者操作同一个对象
- 在整个程序空间使用全局变量,共享资源
- 大规模系统中,为了性能的考虑,需要节省对象的创建时间等等。
因为Singleton模式可以保证为一个类只生成唯一的实例对象,所以这些情况,Singleton模式就派上用场了。

实现单例模式的一般步骤
a) 构造函数私有化
b) 提供一个全局的静态方法(全局访问点)
c) 在类中定义一个静态指针,指向本类的变量的静态变量指针

1.简单的单例模式(懒汉模式)
实例:


#include "iostream"
using namespace std;

class Singleton
{
private:
    Singleton(){  }

public:
    static Singleton *getInstance()
    {
        if (m_uniqueInstance == NULL)
        {
            m_uniqueInstance = new Singleton;

        }
        return m_uniqueInstance;
    }
private:
    static Singleton *m_uniqueInstance;
};

Singleton *Singleton::m_uniqueInstance = NULL;

int main(int argc, char *args[])
{

    Singleton *s1 = Singleton::getInstance();
    Singleton *s2 = Singleton::getInstance();

    if (s1 == s2)
        cout << "s1和s2是同一个对象";
    else
        cout << "s1和s2不是同一个对象";



    getchar();
    return 0;
}

运行结果:
这里写图片描述

优点:创建过程十分简单
缺点:每次实例化都要先判断,并且在多线程情况下,容易出现未知错误,例如在A线程实例化单例时,刚给单例分配好内存,但是没返回,此时cpu切换到线程B执行单例,由于没有返回,线程B判断单例此时还是为NULL,继续给它分配内存,这样就会造成AB实例化了两个对象,而不是访问的一个实例化对象。

2.急切实例化:
急切实例化是在静态初始化中就创建单例
实例:


#include "iostream"
using namespace std;

class Singleton
{
private:
    Singleton(){  }

public:
    static Singleton *getInstance()
    {

        return m_uniqueInstance;
    }
private:
    static Singleton *m_uniqueInstance;
};

Singleton *Singleton::m_uniqueInstance = new Singleton;

int main(int argc, char *args[])
{

    Singleton *s1 = Singleton::getInstance();
    Singleton *s2 = Singleton::getInstance();

    if (s1 == s2)
        cout << "s1和s2是同一个对象";
    else
        cout << "s1和s2不是同一个对象";
    getchar();
    return 0;
}

运行结果
这里写图片描述
Singleton *Singleton::m_uniqueInstance = new Singleton;
唯一不同的就是我们在初始化的过程中就已经创建好单例。在静态getInstance中不用实例化直接返回。
优点:保证了线程安全。
缺点:在单例类本身占十分多的资源的情况下会影响程序效率。

3.懒汉式改进(采用同步机制)
如果只采用同步机制,那么单例类每次实例时都会进行线程等待,但是由于只有在第一次创建单例时才需要真正的同步,如果,对象已经创建好了,就不需要同步了,因此,再次改进

#include "iostream"
#include <windows.h>


using namespace std;



class Singleton
{
private:
    Singleton(){  }

public:
    static Singleton *getInstance()
    {

        if (m_uniqueInstance == NULL)
        {
            Lock();//借用其它类来实现,如boost
            m_uniqueInstance = new Singleton;
        }
        UnLock();
        return m_uniqueInstance;
    }
private:
    static Singleton *m_uniqueInstance;
};

Singleton *Singleton::m_uniqueInstance = NULL;

int main(int argc, char *args[])
{

    Singleton *s1 = Singleton::getInstance();
    Singleton *s2 = Singleton::getInstance();

    if (s1 == s2)
        cout << "s1和s2是同一个对象";
    else
        cout << "s1和s2不是同一个对象";



    getchar();
    return 0;
}

程序的并发执行往往带来与时间有关的错误,甚至引发灾难性的后果。这需要
引入同步机制。使用多进程与多线程时,有时需要协同两种或多种动作,此过程就
称同步(Synchronization)。引入同步机制的第一个原因是为了控制线程之间的资源
同步访问,因为多个线程在共享资源时如果发生访问冲突通常会带来不正确的后果。
例如,一个线程正在更新一个结构,同时另一个线程正试图读取同一个结构。结果,
我们将无法得知所读取的数据是新的还是旧的,或者是二者的混合。第二个原因是
有时要求确保线程之间的动作以指定的次序发生,如一个线程需要等待由另外一个
线程所引起的事件。
为了在多线程程序中解决同步问题,Windows提供了四种主要的同步对象,
每种对象相对于线程有两种状态——信号状态(signal state)和非信号状态(nonsignal
state)。当相关联的同步对象处于信号状态时,线程可以执行(访问共享资源),反
之必须等待。这四种同步对象是:
(1)事件对象(Event)。事件对象作为标志在线程间传递信号。一个或多个线
程可等待一个事件对象,当指定的事件发生时,事件对象通知等待线程可以开始执
行。它有两种类型:自动重置(auto-reset)事件和手动重置(manual-reset)事件。
(2)临界区(Critical Section)。临界区对象通过提供一个进程内所有线程必须
共享的对象来控制线程。只有拥有那个对象的线程可以访问保护资源。在另一个线
程可以访问该资源之前,前一个线程必须释放临界区对象,以便新的线程可以索取
对象的访问权。
(3)互斥量(Mutex Semaphore)。互斥量的工作方式非常类似于临界区,只是
互斥量不仅保护一个进程内为多个线程使用的共享资源,而且还可以保护系统中两
个或多个进程之间的的共享资源。
(4)信号量(Semaphore)。信号量可以允许一个或有限个线程访问共享资源。
它是通过计数器来实现的,初始化时赋予计数器以可用资源数,当将信号量提供给
一个线程时,计数器的值减1,当一个线程释放它时,计数器值加1。当计数器值小
于等于0时,相应线程必须等待。信号量是Windows98同步系统的核心。从本质上
讲,互斥量是信号量的一种特殊形式。
Windows/NT还提供了另外一种Windows95没有的同步对象:可等待定时器
(Waitable Timer)。它可以封锁线程的执行,直到到达某一具体时间。这可以用于
后台任务。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值