1 本篇主要讨论下多线程下的单例模式实现:

  首先是 double check 实现方式: 这种模式可以满足多线程环境下,只产生一个实例。

    template<typename T>
class dclsingleton
{
public:
static T& GetInstance()
{
if(NULL == value_)
{
MutexGuard mg(mutex_);
if (NULL == value_)
{
value_ = new T;
}
} return *value_;
}
protected:
dclsingleton() { std::cout << "dclsingleton constuctor called" << std::endl; }
dclsingleton(const dclsingleton &dcl) {} private:
static T* value_;
static Mutex mutex_;
};

  但是这种实现存在除bug的隐患, 问题就在: value_ = new T; 上。《程序员的自我修养》上指出:

  这样的代码是有问题的,问题的来源在于 cpu 的乱序执行。c++里的new 包含了两步。

  (1)分配内存

  (2)调用构造函数

  所以 value_ = new T;  实际上包含了三步:

  (1)分配内存

  (2)在分配内存的位置上调用构造函数  

  (3)将内存地址赋值给 value_;

  这三步中,(2), (3)两步是可以颠倒的,也就是说,可能出现,先执行(3)这是 value_已经不为NULL, 当出现另一个对GetInstance的并发调用,if 内的 value_ != NULL于是返回,但是还没有调用构造函数。于是使用这个指针的时候,就会导致崩溃。

  这时候需要保证(2), (3)的执行顺序,通常需要加上内存屏障,保证一定保证(2)执行完以后,再执行(3)

  这里我加上了__sync_synchronize(); 后 实现是这样的:

  

       static T& GetInstance()
{
if(NULL == value_)
{
MutexGuard mg(mutex_);
if (NULL == value_)
{
T* tmp = static_cast<T*>(operator new (sizeof(T)));
new (tmp) T();
__sync_synchronize();
value_ = tmp;
}
} return *value_;
}

    这样便可以既保证多线程环境安全,又保证不会出现上面的问题。

2. 加上内存屏障的示例代码:dcl_single.h

  

#ifndef __DCL_SINGLE_H
#define __DCL_SINGLE_H #include <iostream> namespace yl
{
class Mutex
{
public:
Mutex()
{
pthread_mutex_init(&mutex_, NULL);
}
~Mutex()
{
pthread_mutex_destroy(&mutex_);
} public:
void Lock()
{
pthread_mutex_lock(&mutex_);
}
void UnLock()
{
pthread_mutex_unlock(&mutex_);
} private:
pthread_mutex_t mutex_;
}; class MutexGuard
{
public:
MutexGuard(Mutex& m) : mutex_(m)
{
mutex_.Lock();
} ~MutexGuard()
{
mutex_.UnLock();
} private:
Mutex mutex_;
}; template<typename T>
class dclsingleton
{
public:
static T& GetInstance()
{
if(NULL == value_)
{
MutexGuard mg(mutex_);
if (NULL == value_)
{
T* tmp = static_cast<T*>(operator new (sizeof(T)));
new (tmp) T();
__sync_synchronize();
value_ = tmp;
}
} return *value_;
}
protected:
dclsingleton() { std::cout << "dclsingleton constuctor called" << std::endl; }
dclsingleton(const dclsingleton &dcl) {} private:
static T* value_;
static Mutex mutex_;
}; template<typename T>
T* dclsingleton<T>::value_ = NULL; template<typename T>
Mutex dclsingleton<T>::mutex_;
} #endif

  singletonTest.cpp

#include "dcl_single.h"
#include <iostream> namespace yl
{
class MgrSg : public dclsingleton<MgrSg>
{ private:
friend class dclsingleton <MgrSg>;
MgrSg(){ std::cout << "MgrSg: constructor called" << std::endl; }
~MgrSg() { std::cout << "MgrSg: desconstructor called" << std::endl; }
public:
void print()
{
std::cout << "print called" << std::endl;
}
};
} int
main(void)
{
using namespace yl; MgrSg::GetInstance().print();
return ;
}

3. 还可以用 unix 下的 pthread_once 来实现单例模式:

  

template <typename T>
class MySingleton
{
public:
static T & getInstance()
{
pthread_once(&ponce_, &MySingleton::init);
return *instance;
} protected:
MySingleton() {}
MySingleton(const MySingleton&) {}
private:
static void init()
{
instance = new T();
}
private:
static pthread_once_t ponce_;
static T *instance;
}; template<typename T>
pthread_once_t MySingleton<T>::ponce_ = PTHREAD_ONCE_INIT; template<typename T>
T *MySingleton<T>::instance = nullptr;
}

4.我自己遇到的就是以上两种情况,若是希望了解更全面,可参考下边:

  http://www.cnblogs.com/liyuan989/p/4264889.html

5. 水平有限,望及时指出错误。谢谢

  

c++之单例模式的更多相关文章

  1. C++实现线程安全的单例模式

    在某些应用环境下面,一个类只允许有一个实例,这就是著名的单例模式.单例模式分为懒汉模式,跟饿汉模式两种. 首先给出饿汉模式的实现 template <class T> class sing ...

  2. 23种设计模式--单例模式-Singleton

    一.单例模式的介绍 单例模式简单说就是掌握系统的至高点,在程序中只实例化一次,这样就是单例模式,在系统比如说你是该系统的登录的第多少人,还有数据库的连接池等地方会使用,单例模式是最简单,最常用的模式之 ...

  3. angular2系列教程(十)两种启动方法、两个路由服务、引用类型和单例模式的妙用

    今天我们要讲的是ng2的路由系统. 例子

  4. java设计模式之--单例模式

    前言:最近看完<java多线程编程核心技术>一书后,对第六章的单例模式和多线程这章颇有兴趣,我知道我看完书还是记不住多少的,写篇博客记录自己所学的只是还是很有必要的,学习贵在坚持. 单例模 ...

  5. 设计模式C#合集--单例模式

    单例模式 代码: 第一种: private static Singleton singleton = null; private Singleton() { } public static Singl ...

  6. 设计模式之单例模式(Singleton)

    设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...

  7. GOF23设计模式之单例模式

    ·核心作用: -保证一个类只有一个实例,并且提供一个访问该实例的全局访问点. ·常见应用场景: -Windows的Task Manager(任务管理器)就是很典型的单例模式 -Windows的Recy ...

  8. GJM : C#设计模式(1)——单例模式

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  9. PHP设计模式(四)单例模式(Singleton For PHP)

    今天讲单例设计模式,这种设计模式和工厂模式一样,用的非常非常多,同时单例模式比较容易的一种设计模式. 一.什么是单例设计模式 单例模式,也叫单子模式,是一种常用的软件设计模式.在应用这个模式时,单例对 ...

  10. java设计模式之单例模式(几种写法及比较)

    概念: Java中单例模式是一种常见的设计模式,单例模式的写法有好几种,这里主要介绍三种:懒汉式单例.饿汉式单例.登记式单例. 单例模式有以下特点: 1.单例类只能有一个实例. 2.单例类必须自己创建 ...

随机推荐

  1. LeetCode题目_Reverse Integer

    最近在LeetCode上做题,写点东西记录一下,虽然自己做的都是些很水的题目,但是重在练手. 题号7:Reverse Integer,题目描述: Reverse digits of an intege ...

  2. 16.Update Methods-官方文档摘录

    这里没什么好说的,直接贴文了 MongoDB provides the following methods for updating documents in a collection: db.col ...

  3. Linux下的内核抢占

    2017-03-03 很遗憾之前在介绍进程调度的文章中,虽然涉及到了内核抢占,但是却没有对其进行深入介绍,今天就稍微总结下内核抢占. 内核抢占在一定程度上减少了对某种事件的响应延迟,这也是内核抢占被引 ...

  4. LayoutInflater的动态增加控件

    在实际开发中LayoutInflater这个类是非常有用的,它的作用类似于 findViewById(),不同点是LayoutInflater是用来找layout下xml布局文件. 而findView ...

  5. MongoDB学习笔记系列~目录

    MongoDB学习笔记~环境搭建 (2015-03-30 10:34) MongoDB学习笔记~MongoDBRepository仓储的实现 (2015-04-08 12:00) MongoDB学习笔 ...

  6. 查看pc ip地址

    1.使用Windows+R键打开“运行”窗口,然后输入CMD进入命令提示窗口 2.进入命令窗口之后,输入:ipconfig/all 回车即可看到整个电脑的详细的IP配置信息

  7. 20165324 Java实验五 网络编程与安全

    20165324 Java实验五 网络编程与安全 一.实验报告封面 课程:Java程序设计 班级:1653班 姓名:何春江 学号:20165324 指导教师:娄嘉鹏 实验日期:2018年5月28日 实 ...

  8. vs git 推送远程会失败.

    Gitblit使用admin创建版本库.   使用VS无法推送到远程服务器. VS 2017 Git failed with a fatal error 可能是帐号不应不上.   本地上帐号与服务器的 ...

  9. java反射之构造方法(三)

    一. 1. 二.获取类的构造方法信息. ######################################################################## 三.

  10. HDU - 4675 GCD of Sequence (莫比乌斯反演+组合数学)

    题意:给出序列[a1..aN],整数M和k,求对1-M中的每个整数d,构建新的序列[b1...bN],使其满足: 1. \(1 \le bi \le M\) 2. \(gcd(b 1, b 2, -, ...