七、单例设计模式共享数据分析、解决、call_once

一、设计模式大概谈

代码的一些写法,与常规的写法不太一样,程序灵活,维护起来很方便,但是别人接管、阅读代码很痛苦。

用设计模式理念写出来的代码很晦涩。<< head first>>

老外应付特别大的项目时候,把项目开发经验、模块划分经验,总结成设计模式。

二、单例设计模式

使用频率高。

单例:整个项目中,有某个特殊或某些特殊的类,属于该类的对象,我只能创建1个,多了我就创建不了了。

单例类(构造函数为private);

 1 class A{//单例类
 2 private:
 3     A() {} //私有化构造函数,就不能用A a;这种方式来创建对象了
 4     static A* m_instance;//静态成员变量
 5 public:
 6     static A* GetInstance(){
 7         if(m_instance == NULL){
 8             m_instance = new A();
 9             static huishou cl;
10
11         }
12         return m_instance;
13     }
14
15     class huishou{//类中套类,用来释放对象
16     public:
17         ~huishou(){
18             if(A::m_instance){//如果这个m_instance不是空,那么就得释放A对象
19             delete A::m_instance;
20             A::m_instance=NULL;
21             }
22         }
23     }
24
25 };
26
27 //静态变量初始化
28 A* A::m_instance=NULL;
29
30 A *p_a = A::GetInstance();//第一次调用函数,返回m_instance就非空了,当再次创建就不行了。

三、单例设计模式共享数据问题分析、解决

有时候需要在我们自己创建的线程(不是主线程)中创建A这个单例类的对象,这种线程可能最少2个。我们可能会面临

GetInstance()这个成员函数要互斥,例如:

 1 using namespace std;
 2 std::mutex resource_mutex;
 3
 4
 5 class A{//单例类
 6 private:
 7     A() {} //私有化构造函数,就不能用A a;这种方式来创建对象了
 8     static A* m_instance;//静态成员变量
 9 public:
10     static A* GetInstance(){
11         std::unique_lock<std::mutex> mymutex(resource_mutex);//会自动加锁
12         if(m_instance == NULL){
13             m_instance = new A();
14             static huishou cl;
15
16         }
17         return m_instance;
18     }
19
20     class huishou{//类中套类,用来释放对象
21     public:
22         ~huishou(){
23             if(A::m_instance){//如果这个m_instance不是空,那么就得释放A对象
24             delete A::m_instance;
25             A::m_instance=NULL;
26             }
27         }
28     }
29
30 };
31
32 //静态变量初始化
33 A* A::m_instance=NULL;
34
35 //线程入口函数
36 void mythread(){
37     cout << "thread is begining!" <<endl;
38     A* p_a = A::GetInstance();//这里会出问题
39     cout << "this thread over" << endl;
40     return;
41 }
42
43 int main(){
44     std::thread thread1(mythread);
45     std::thread thread2(mythread);
46     thread1.join();
47     thread2.join();
48     return 0;
49
50 }

两个线程的入口函数是相通的,有一种情况可能会发生:当thread1正好创建A对象(正在执行GetInstance)的时候任务被切换到了thread2,那么thread2也会同时执行到GetInstance,相当于两个线程同时执行这个函数,这就坏事了。所以要来一个锁,就行了。

上面的效率太低了,相当于每次创建A都要调用get函数,还要锁上,相当于你这么复杂的步骤,只是为了解决初始化时的问题,这几很低效率了。

怎样高效解决呢?看下面代码:

 1     static A* GetInstance(){
 2         //双重锁定提高效率
 3         if(m_instance==NULL)//双重锁定,双重检查
 4         {         //这段函数也就是只执行一次
 5             std::unique_lock<std::mutex> mymutex(resource_mutex);//会自动加锁
 6             if(m_instance == NULL){
 7                 m_instance = new A();
 8                 static huishou cl;
 9             }
10         }
11         return m_instance;
12     }

如何提高效率的?

我们知道如果if(m_instance!=NULL)条件成立,表示肯定已m_instance已经被new过了;

如果if(m_instance==NULL),不代表m_instance一定没有被new过,比如上面说的那种特殊情况。

第一个if条件成功的情况就是第一次创建A对象或者几个线程同时第一次创建A对象的手,才会进入第一个if执行语句中,然后就加锁。。。。。。

一旦这个对象已经创建了,那么第一个if里面的执行语句就根本不会再执行了了。也即是说,第一个if就专门是针对出创A对象或多个线程初创A对象的情况,一旦A对象有了,就再也不会执行里面的语句了,效率高了很多。

四、std::call_once()

函数模板

能够保证函数a只被调用一次。

具备互斥量这种能力,效率上比互斥量消耗更少。

需要与一个标记结合使用,这个标记std::once_flag是一个结构。

根据这个标记来决定对应的函数a是否被执行,调用call_once成功后,call_once()就把这个标记设置为一种已调用状态,对应的a函数就不会再被执行了。

 1 using namespace std;
 2 std::once_flag m_flag;//系统定义的标记
 3
 4 class A{//单例类
 5     static void creatInstance(){//只被调用一次,不加说明都默认成是private
 6         m_instance = new A();
 7         static huishou cl;
 8     }
 9 private:
10     A() {} //私有化构造函数,就不能用A a;这种方式来创建对象了
11     static A* m_instance;//静态成员变量
12 public:
13     static A* GetInstance(){
14         //如果两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕creatInstance()
15         std::call_once(m_flag,creatInstance);
16         return m_instance;
17     }
18
19     class huishou{//类中套类,用来释放对象
20     public:
21         ~huishou(){
22             if(A::m_instance){//如果这个m_instance不是空,那么就得释放A对象
23             delete A::m_instance;
24             A::m_instance=NULL;
25             }
26         }
27     }
28
29 };
30
31 //静态变量初始化
32 A* A::m_instance=NULL;
33
34 //线程入口函数
35 void mythread(){
36     cout << "thread is begining!" <<endl;
37     A* p_a = A::GetInstance();//这里会出问题
38     cout << "this thread over" << endl;
39     return;
40 }
41
42 int main(){
43     std::thread thread1(mythread);
44     std::thread thread2(mythread);
45     thread1.join();
46     thread2.join();
47     return 0;
48
49 }

PS:一般建议在主线程中创建单例对象

原文地址:https://www.cnblogs.com/pacino12134/p/11240699.html

时间: 2024-10-01 00:28:55

七、单例设计模式共享数据分析、解决、call_once的相关文章

单例设计模式和多线程

单例设计模式 单例:整个项目中,有某个类或者某些特殊的类,属于该类的对象只能建立一个. #include<iostream> using namespace std; class MyCAS { private: MyCAS(){} private: static MyCAS *m_instance; public: static MyCAS *GetInstance() ///得到对象的接口函数 { if(m_instance==NULL) { m_instance = new MyCAS(

设计模式之单例设计模式

一.何为单例设计模式 单例模式,顾名思义就是单个实例,程序中某个类只有一个实例存在.通常实在需要共享某个资源避免资源损耗的情况下使用到的. 二.单例设计模式的代码实现 一说到单例模式的概念,我们首先会想到下面的这种的写法 public class SingleInstance { private static SingleInstance singleInstance; /** * 单例模式 * @return */ public static SingleInstance getSingleI

java的单例设计模式

/* 单例设计模式解决的问题:可以保证一个类在内存中对象唯性一性(数据实现了共享). 如何保证对象唯一性呢?1,不允许其他程序用 ,2,在该类创建一个本实例.3,对外提供一个方法让其他程序可以获取该象.步骤:1,私有化该类构造函数. 2.通过 new 在本类中创建一个对象. 3,定义一个公有的方法,将创建对象返回.*/ public class Test1 { public static void main(String[] args) { // TODO 自动生成的方法存根 Test5 t1=

GOF设计模式之1:单例设计模式

1.单例设计模式核心作用: 保证一个类只有一个实例,并且提供了访问该实例的全局访问点 2.常见应用场景: window的任务管理器 项目中读取配置文件一般也是一个单例模式 数据库连接池的设计也是采用单例模式,因为数据库连接是一种数据库资源 操作系统的文件管理系统,也是单例模式,一个操作系统只能有一个文件系统 Application也是单例的应用(Servlet编程或者Android的Application类) 在Spring中,每个bean默认也是单例的,这样的有点儿事Spring容器可以管理

黑马程序员_09. api-线程及单例设计模式

黑马程序员_api-线程及单例设计模式 a.明确以下概念: 1.进程:是一个正在执行中的程序.每一个进程执行都有一个执行顺序.该顺序是一个执行路径,或叫一个控制单元. 2.线程:就是进程中的一个独立的控制单元.线程在控制着进程的执行,一个进程中至少有一个线程. 3.多线程:如果一个进程中存在着多个控制单元,那么这个进程是一个多线程的应用程序.JVM启动时是一个多线程. b.创建线程的两种方式 1. java已经提供了对线程这类事物的描述.就是Thread类.并且这个类把要运行的代码存放在了run

菜鸟之路-浅谈设计模式之单例设计模式

单例设计模式 定义:确保一个类仅仅有一个实例.并且自行实例化并向整个系统提供这个实例. 单例模式是一种经常使用的软件设计模式.在它的核心结构中仅仅包括一个被称为单例的特殊类. 通过单例模式能够保证系统中一个类仅仅有一个实例并且该实例易于外界訪问,从而方便对实例个数的控制并节约系统资源.假设希望在系统中某个类的对象仅仅能存在一个,单例模式是最好的解决方式. 关于单例设计模式的动机 对于系统中的某些类来说,仅仅有一个实例非常重要,比如.一个系统中能够存在多个打印任务.可是仅仅能有一个正在工作的任务:

Java设计模式之一 单例设计模式

1.什么叫设计模式: 设计模式的概念首先来源于其它行业:建筑业,在早起建房子的时候,肯定是经验缺乏.显得杂乱无序的,这就会造成很多问题,在行业发展过程,通过不断的经验积累,前辈们针对这些问题提出了合理解决方案,这就是设计模式,参照设计模式往往可以解决很多问题,在计算机编程方面,也会出现类似问题,所以牛人们把这些解决问题的方案进行归类和总结,形成了面向对象编程的23种设计模式. 2.单例模式(特点): Java中单例模式定义:"一个类有且仅有一个实例,并且自行实例化向整个系统提供."通过

Java设计模式—单例设计模式(Singleton Pattern)全然解析

转载请注明出处:http://blog.csdn.net/dmk877/article/details/50311791 相信大家都知道设计模式,听的最多的也应该是单例设计模式,这种模式也是在开发中用的最多的设计模式,可能有非常多人会写几种设计模式.那么你是否知道什么是设计模式?为什么会有单例设计模式即它的作用是什么?单例模式有哪些写法?对于这种问题.可能有部分童鞋并不能非常好的回答,没关系今天就和大家一起来具体的学习下单例设计模式,相信通过学习本篇你将对单例设计模式有个具体的理解. 如有谬误欢

JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制

JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是class对象 我们在上节验证了同步函数的锁是this,但是对于静态同步函数,你又知道多少呢? 我们做一个这样的小实验,我们给show方法加上static关键字去修饰 private static synchronized void show() { if (tick > 0) { try { Thread