`

C++多线程的Singleton(1)

阅读更多

C++多线程的Singleton(2)

 

Singleton是我使用过的最多的设计模式,也是日常工作中大家会经常用到的设计模式。其实,在C++里面写一个Singleton,不是一件非常容易的事情,以至于《C++设计新思维》里面花了一章内容专门讲解。难点在哪里呢?其实就是两个:

(1)多线程的并发性 (如果你的程序是单线程的,那么就没有这个问题)

(2)生命周期

 

下面我们就开始这个旅程。另外一点,我现在使用C++的原则是KISS,保持设计和代码的简单性。

 

首先,我们先来看看这两个问题。

(1)多线程的并发性,这不难理解。如果在单线程模式下,我们通常会这么写Singleton:

// Singleton.h
class Singleton
{
  public:
     ~Singleton(){}
     static Singleton& getInstance();

  private:
     Singleton(){}
     
};

// Singleton.cpp

/* static */
Singleton& Singleton::getInstance()
{
  static Singleton *instance = new Singleton;
  return &instance;
} 

  

 这种方法是按照《Effective C++》里面的建议,不使用class static变量,而使用函数static变量。这个是延迟初始化,如果整个过程没有函数调用Singleton::getInstance(),那么就不会有Singleton这个对象生成。为什么返回一个Reference,而不是一个指针,是因为这样不容易被误delete。可是如果是多线程呢?有Java经验的同学都会想到下面这个方法:

 

// Singleton.h 错误的实例
class Singleton
{
  public:
     ~Singleton(){}
     static Singleton& getInstance();

  private:
     Singleton(){}
     static Lock lock_;
};

// Singleton.cpp

/* static */
Lock Singleton::lock_;

Singleton& Singleton::getInstance()
{
  static Singleton *instance = NULL;
  if (NULL == instance) // thread B Pos1
  {
    LockHandler handler(lock_);  
    if (NULL == instance)
    {
      instance = new Singleton;  // thread A   Pos2
    }
  }
  return &instance;
} 

 (注解:Lock是类似与封装了pthread_mutex_t的类,具有lock(), unlock(), trylock()这样的方法;而LockHandler的构造函数就会调用lock_.lock(),析构函数会调用lock_.unlock(),这是一种RIIA的惯用法)。这段代码非常Java的Singleton代码,它有一个响亮的名字:两次检查。

 

public class Singleton {
    private Singleton(){}
    private static Singleton instance;
    public static Singleton getInstance() {
        if (instance == null) {
          synchronized(Singleton.class) {
            if (instance == null) {
              instance = new Singleton();  
            }
          }
        }
    }
}

上面这段Java代码在Java5之后是正确的,在Java5之前,在有些平台上这段代码是有bug的。那C++的两次检查呢?是错误的。知道为什么这段代码是错误的,只会让让你很郁闷,因为instance = new Singleton这句话,根据正常的理解,应该是Singleton分好内存,然后再调用构造函数,然后再把那个地址赋值给instance。可是事实上这是不一定的,有可能先完成这次赋值,再调用构造函数。也许你应该明白为什么有问题了吧。假设threadA到了pos2那个地方,此时threadB刚好来到pos1,然后它发现instance==null不成立,于是threadB就可以使用instance了。可是此时,instance指向的对象还没有正常的调用构造函数。换句话说,threadB使用了一个没有被正确初始化的对象。看到这里也许你要哭了,没错,我也哭了。这不是我们程序员本需要考虑的问题,可是它就是像座山一样在那里。没办法,如果你使用C++,那么请接受它吧。我可以说这种问题很难测试到,也许它会跟随你的系统几个月甚至上年,可是有一天它突然崩溃了,你才知道原来是这样造成的。没办法,那我们退回到一个保守的地方:

 

// Singleton.h
class Singleton
{
  public:
     ~Singleton(){}
     static Singleton& getInstance();

  private:
     Singleton(){}
     static Lock lock_;
};

// Singleton.cpp

/* static */
Lock Singleton::lock_;

Singleton& Singleton::getInstance()
{
  static Singleton *instance = NULL;
  LockHandler handler(lock_); 
  if (NULL == instance) // thread B Pos1
  {
    instance = new Singleton;  // thread A   Pos2
  }
  return &instance;
} 

 这个代码是对的,正确的。可是它有些效率问题,因为你每次访问这个资源的时候,都需要去竞争这个lock_。我们需要继续优化这个。(未完待续)

 

0
1
分享到:
评论
1 楼 lovedame 2013-04-28  
// Singleton.h 错误的实例  
class Singleton  
{  
  public:  
     ~Singleton(){}  
     static Singleton& getInstance();  
  
  private:  
     Singleton(){}  
     static Lock lock_;  
};  
  
// Singleton.cpp  
  
/* static */  
Lock Singleton::lock_;  
  
Singleton& Singleton::getInstance()  
{  
  static Singleton *instance = NULL;  
  if (NULL == instance) // thread B Pos1  
  {  
    LockHandler handler(lock_);    
    if (NULL == instance)  
    { 
//改动之处------------------------------------------改动之处 
      Singleton *newInstance = new Singleton;
      instance = newSingleton;  // thread A   Pos2  
    }  
  }  
  return &instance;  
}   


楼主看这样可以吗 没在多线程下测试

相关推荐

    C++中多线程与Singleton的那些事儿

    前言  前段时间在网上看到了个的面试题,大概...本文主要将从基本的单线程中的Singleton开始,慢慢讲述多线程与Singleton的那些事。  单线程  在单线程下,下面这个是常见的写法: template class Singleton

    C++CLI中实现singleton模式

    双重检测锁(Double-Checked Locking)实现的Singleton模式在多线程应用中有相当的价值。在ACE的实现中就大量使用ACE_Singleton模板类将普通类转换成具有Singleton行为的类。这种方式很好地消除了一些重复代码臭味,...

    Linux多线程服务端编程:使用muduo C++网络库

    第1部分C++ 多线程系统编程 第1章线程安全的对象生命期管理3 1.1当析构函数遇到多线程. . . . . . . . . . . . . . . . .. . . . . . . . . . . 3 1.1.1线程安全的定义. . . . . . . . . . . . . . . . .. . . . . ....

    C++线程安全的单例模式

     需要用锁,来保证其线程安全性:原因:多个线程可能进入判断是否已经存在实例的if语句,从而non thread safety.  使用double-check来保证thread safety.但是如果处理大量数据时,该锁才成为严重的性能瓶颈。 ...

    C++线程安全的单例模式讲解

    需要用锁,来保证其线程安全性:原因:多个线程可能进入判断是否已经存在实例的if语句,从而non thread safety。 使用double-check来保证thread safety。但是如果处理大量数据时,该锁才成为严重的性能瓶颈。 1、...

    Singleton模式源程序

    感谢李建忠老师,这里仅是源程序,还包括多线程的实现。

    C++轻量级通用插件框架源码

    本插件机制所提供的内部实现文件考虑了线程安全性,允许多线程访问而不冲突,同时采用的是轻量级的锁定机制(计数原子锁定),运行开销很小。 g) 跨版本 允许不同版本的VC++开发的插件相互调用对方的接口,虽然...

    轻量级、易用、快速的日志库,仅提供日志写入前端 C++源代码

    多个线程间的日志不穿插干扰. 日志线程不能干扰主程序的运行逻辑. 易读性 每条日志记录占用一行空间,便于 awk 等工具的时候方便查找, 查看教程. 日志信息包含必要的信息,包括日期时间、线程id、日志等级、日志发生...

    设计模式,软件开发者必读

    2.1.2 多线程安全的SINGLETON类 12 2.1.3 双重锁定SINGLETON 13 2.1.4 静态初始化SINGLETON 13 2.1.5 SINGLETON的子类化问题 14 2.1.6 SINGLETON销毁 15 2.1.7 SINGLETON模式扩展 16 2.2 FACTORY METHOD工厂方法模式...

    Visual C++ 编程资源大全(英文源码 网络)

    25.zip SMTP MFC Classes SMTP协议类(6KB)<END><br>103,26.zip Pre-emptive Multithreading Web Spider 多线程的网络蜘蛛(7KB)<END><br>104,27.zip Updated SMTP Class 更新的SMTP类(5KB)<END><br...

    使用设计模式中的单例模式来实现C++的boost库

    需要用锁,来保证其线程安全性:原因:多个线程可能进入判断是否已经存在实例的if语句,从而non thread safety。 使用double-check来保证thread safety。但是如果处理大量数据时,该锁才成为严重的性能瓶颈。 1、...

    javaee底层源码-DesignModels:C++设计模式

    是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。 3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机...

    汪文君高并发编程实战视频资源全集

    │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、介绍三种高效优雅的Singleton实现方式.wmv │ 高并发编程第二阶段04讲、多线程的休息室WaitSet详细...

    汪文君高并发编程实战视频资源下载.txt

    │ 高并发编程第二阶段02讲、介绍四种Singleton方式的优缺点在多线程情况下.wmv │ 高并发编程第二阶段03讲、介绍三种高效优雅的Singleton实现方式.wmv │ 高并发编程第二阶段04讲、多线程的休息室WaitSet详细...

    常见设计模式—单例模式(Singleton)

    单例模式(Singleton Pattern)是设计模式中最简单的模式之一,属于创建型模式。这种设计模式主要是类的对象只有一个实例,不需要每次new 创造。而我们要做的的就是确保这个对象创建的唯一。然后根据一些特征进行...

    Visual C++ 编程资源大全(英文源码 表单)

    67.zip A Generalized Parsing Class for MFC 一个普通的MFC解析类(5KB)<END><br>68,69.zip Creating Singleton Objects using Visual C++ 使用VC++创建一个单独的对象(9KB)<END><br>69,69.zip Smart...

    leetcode2-StayFoolish:保持饥饿,保持愚蠢!

    leetcode 2 个人持续学习总结项目 这个项目用来存放自己平时学习与总结的内容 DataStructure_Cs ...面试题2:实现Singleton模式:懒汉式、饿汉式、多线程安全单例等 Lua lua-5.2.1 源码学习 todo 学习lua vm 参考

    二十三种设计模式【PDF版】

    设计模式之 Singleton(单态/单件) 阎宏博士讲解:单例(Singleton)模式 保证一个类只有一个实例,并提供一个访问它的全局访问点 设计模式之 Factory(工厂方法和抽象工厂) 使用工厂模式就象使用 new 一样频繁. ...

    JAVA面试题最全集

    多线程,用什么关键字修饰同步方法?stop()和suspend()方法为何不推荐使用? 59.使用socket建立客户端与服务器的通信的过程 60.JAVA语言国际化应用,Locale类,Unicode 61.描述反射机制的作用 62.如何读写一个...

    Objective C 单例模式设计源码

    平时,我们常用单例模式的地方通常是多线程。 因为Objective C传承了Smalltalk语言,所以在Objective C中实现单例模式和C++和C#以及Java都不太一样。因为要保证类型对象的单一性,所以就要考虑Objective C在实例化...

Global site tag (gtag.js) - Google Analytics