线程安全的单例模式_第1页
线程安全的单例模式_第2页
线程安全的单例模式_第3页
线程安全的单例模式_第4页
线程安全的单例模式_第5页
已阅读5页,还剩2页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、线程安全的单例模式、/、刖旨单例模式(SingletonPattern)是最简单的、也是我们很常用的一种设计模式。保证一个类仅有一个实例,并提供一个该实例的全局访问点。那么在多线程的环境,怎么才能更好的确保线程安全呢?实现1饿.汉模式饿汉模式使用一个静态成员变量,程序启动即完成构造,不用考虑线程安全的问题,C+11中static的特性:如果当变量在初始化的时候,并发同时进入声明语句,并发线程将会阻塞等待初始化结束。classSingletonpublic:staticSingleton*GetInstance()returninstance_;if(instance_!=nullptr)del

2、eteinstance_;private:Singleton()=default;Singleton&operator=(constSingleton&)=delete;Singleton(constSingleton&singleton2)=delete;private:staticSingleton*instance_;_intmain()Singleton*s1=Singleton:GetInstance();Singleton:DestreyInstance();return0;关于资源的释放上例中我们使用了一个静态的成员函数来释放堆上的资源,需要手动调用,并不是很方便。我们可以使用智

3、能指针或者一个内部类来实现资源的自动释放,也更符合Moderncpp的风格。接下来我们演示如何使用一个内部类来优化饿汉模式。classSingletonpublic:staticSingleton*GetInstance()returninstance_;if(instance_!=nullptr)deleteinstance_;private:classGCpublic:GC()可以在这里销毁所有的资源,例如:b连接、文件句柄等if(instance_!=nullptr)deleteinstance_;instance_=nullptr;staticGCgc;p!:Singleton()=d

4、efault;Singleton&operator=(constSingleton&)=delete;Singleton(constSingleton&singleton2)=delete;private:staticSingleton*instance_;_懒汉模式饿汉方式不论是否需要使用该对象都将其定义出来,可能浪费了内存,或者减慢了程序的启动速度。所以使用懒汉模式进行优化,懒汉模式即延迟构造对象,在第一次使用该对象的时候才进行new该对象。而懒汉模式会存在线程安全问题,最出名的解决方案就是Double-CheckedLockingPattern(DCLP)(双检锁)。使用两次判断来解决线

5、程安全问题并且提高效率。classSingletonpublic:staticSingleton&GetInstance()if(instance_=nullptr)std:lock_guardlock(mutex_);if(instance_=nullptr)instance_.reset(newSingleton);return*instance_;Singleton()=default;private:Singleton()=default;Singleton(constSingleton&)=delete;Singleton&operator=(constSingleton&)=del

6、ete;private:staticstd:unique_ptrinstance_;staticstd:mutexmutex_;std:unique_ptrSingleton:instance_;std:mutexSingleton:mutex_;双检锁的问题DCLP实际上也是存在这严重的线程安全问题的,具体参考原文中有这样一段话:Consideragainthelinethatinitializespinstanee:pInstance=newSingleton;Thisstatementcausesthreethingstohappen:Step1:Allocatememorytohold

7、aSingletonobject.Step2:ConstructaSingletonobjectintheallocatedmemory.Step3:Makepinstaneepointtotheallocatedmemory.Ofcriticalimportanceistheobservationthatcompilersarenotconstrainedtoperformthesestepsinthisorder!Inparticular,compilersaresometimesallowedtoswapsteps2and3.Whytheymightwanttodothatisaques

8、tionwelladdressinamoment.Fornow,letsfocusonwhathappensiftheydo.也就是我们在instance_=newSingleton;时发生了三件事情:申请一块内存来保存单例对象。在申请的内存中调用构造函数。将内存的地址赋值给instance_。不同的编译器表现不一样,它们并不会严格按照这个顺序执行,尤其是有时候允许交换第二步和第三步!也就是说可能会先将内存地址赋值给instance_然后再调用构造函数。这样就会有严重的线程安全问题,比如:线程A刚好申请完内存并将该内存地址赋值给instance_但是此时还没调用构造函数,又刚好此时线程B执行到

9、了if(instance_=nullptr)判断instance_并不为空,返回了该变量,然后调用了该对象的函数,但是该对象还没进行构造。其实就是编译优化导致的一个乱序(reorder)的问题。懒汉模式进一步优化1.使用std:call_oneeC+11中std:call_once和std:once_flag配合使用使得函数可以线程安全的只调用一次。classSingletonpublic:staticSingleton&GetInstance()staticstd:once_flags_flag;std:call_once(s_flag,&()instance_.reset(newSingl

10、eton););return*instance_;Singleton()=default;voidPrintAddress()conststd:coutthisstd:endl;private:Singleton()=default;Singleton(constSingleton&)=delete;Singleton&operator=(constSingleton&)=delete;private:staticstd:unique_ptrinstance_;std:unique_ptrSingleton:instance_;.使用内存屏障classSingletonpublic:stati

11、cSingleton*GetInstance()Singleton*tmp=instance_oad(std:memory_order_relaxed);获取内存屏障std:atomic_thread_fence(std:memory_order_acquire);if(tmp=nullptr)std:lock_guardlock(mutex_);tmp=instance_oad(std:memory_order_relaxed);if(tmp=nullptr)tmp=newSingleton;释放内存屏障std:atomic_thread_fence(std:memory_order_rel

12、ease);instance_store(tmp,std:memory_order_relaxed);atexit(Destructor);returntmp;private:staticvoidDestructor()Singleton*tmp=instance_.load(std:memory_order_relaxed);if(nullptr!=tmp)deletetmp;Singleton()=default;Singleton(constSingleton&)Singleton&operator=(constSingleton&)staticstd:atomicinstance_;s

13、taticstd:mutexmutex_;std:atomicSingleton:instance_;std:mutexSingleton:mutex_;最简单实用的方式好了,说了这么多,前面一顿操作猛如虎,其实最简单实用的还是静态局部变量的方式。classSingletonpublic:Singleton()staticSingleton&GetInstance()staticSingletoninstance;returninstance;private:Singleton()=default;Singleton(constSingleton&)Singleton&operator=(co

14、nstSingleton&);优点:“代码简洁;“利用静态局部变量特性,延迟加载;“利用静态局部变量特性,系统自动回收内存,自动调用析构函数;“静态局部变量初始化时,没有new操作带来的cpu指令reorder操作;“c+11静态局部变量初始化时,具备线程安全;升级为模板templatevtypenameTclassSingletonpublic:staticT&GetInstance()staticTinstance;returninstance;protected:virtualSingleton()Singleton()Singleton(constSingleton&)Singleton&operator=(constSingleton&);使用方式比如我们有一个普通类DesignPattern,它是全局唯一的,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论