七、单例设计模式共享数据分析、解决、call_once
一、设计模式大概谈
代码的一些写法,与常规的写法不太一样,程序灵活,维护起来很方便,但是别人接管、阅读代码很痛苦。
用设计模式理念写出来的代码很晦涩。<< head first>>
老外应付特别大的项目时候,把项目开发经验、模块划分经验,总结成设计模式。
二、单例设计模式
使用频率高。
单例:整个项目中,有某个特殊或某些特殊的类,属于该类的对象,我只能创建1个,多了我就创建不了了。
单例类(构造函数为private);
class A{//单例类
private:
A() {} //私有化构造函数,就不能用A a;这种方式来创建对象了
static A* m_instance;//静态成员变量
public:
static A* GetInstance(){
if(m_instance == NULL){
m_instance = new A();
static huishou cl; }
return m_instance;
} class huishou{//类中套类,用来释放对象
public:
~huishou(){
if(A::m_instance){//如果这个m_instance不是空,那么就得释放A对象
delete A::m_instance;
A::m_instance=NULL;
}
}
} }; //静态变量初始化
A* A::m_instance=NULL; A *p_a = A::GetInstance();//第一次调用函数,返回m_instance就非空了,当再次创建就不行了。
三、单例设计模式共享数据问题分析、解决
有时候需要在我们自己创建的线程(不是主线程)中创建A这个单例类的对象,这种线程可能最少2个。我们可能会面临
GetInstance()这个成员函数要互斥,例如:
using namespace std;
std::mutex resource_mutex; class A{//单例类
private:
A() {} //私有化构造函数,就不能用A a;这种方式来创建对象了
static A* m_instance;//静态成员变量
public:
static A* GetInstance(){
std::unique_lock<std::mutex> mymutex(resource_mutex);//会自动加锁
if(m_instance == NULL){
m_instance = new A();
static huishou cl; }
return m_instance;
} class huishou{//类中套类,用来释放对象
public:
~huishou(){
if(A::m_instance){//如果这个m_instance不是空,那么就得释放A对象
delete A::m_instance;
A::m_instance=NULL;
}
}
} }; //静态变量初始化
A* A::m_instance=NULL; //线程入口函数
void mythread(){
cout << "thread is begining!" <<endl;
A* p_a = A::GetInstance();//这里会出问题
cout << "this thread over" << endl;
return;
} int main(){
std::thread thread1(mythread);
std::thread thread2(mythread);
thread1.join();
thread2.join();
return ; }
两个线程的入口函数是相通的,有一种情况可能会发生:当thread1正好创建A对象(正在执行GetInstance)的时候任务被切换到了thread2,那么thread2也会同时执行到GetInstance,相当于两个线程同时执行这个函数,这就坏事了。所以要来一个锁,就行了。
上面的效率太低了,相当于每次创建A都要调用get函数,还要锁上,相当于你这么复杂的步骤,只是为了解决初始化时的问题,这几很低效率了。
怎样高效解决呢?看下面代码:
static A* GetInstance(){
//双重锁定提高效率
if(m_instance==NULL)//双重锁定,双重检查
{
//这段函数也就是只执行一次
5 std::unique_lock<std::mutex> mymutex(resource_mutex);//会自动加锁
6 if(m_instance == NULL){
7 m_instance = new A();
8 static huishou cl;
9 }
}
return m_instance;
}
如何提高效率的?
我们知道如果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函数就不会再被执行了。
using namespace std;
std::once_flag m_flag;//系统定义的标记 class A{//单例类
static void creatInstance(){//只被调用一次,不加说明都默认成是private
m_instance = new A();
static huishou cl;
}
private:
A() {} //私有化构造函数,就不能用A a;这种方式来创建对象了
static A* m_instance;//静态成员变量
public:
static A* GetInstance(){
//如果两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕creatInstance()
std::call_once(m_flag,creatInstance);
return m_instance;
} class huishou{//类中套类,用来释放对象
public:
~huishou(){
if(A::m_instance){//如果这个m_instance不是空,那么就得释放A对象
delete A::m_instance;
A::m_instance=NULL;
}
}
} }; //静态变量初始化
A* A::m_instance=NULL; //线程入口函数
void mythread(){
cout << "thread is begining!" <<endl;
A* p_a = A::GetInstance();//这里会出问题
cout << "this thread over" << endl;
return;
} int main(){
std::thread thread1(mythread);
std::thread thread2(mythread);
thread1.join();
thread2.join();
return ; }
PS:一般建议在主线程中创建单例对象
七、单例设计模式共享数据分析、解决、call_once的更多相关文章
- Java学习笔记——单例设计模式Singleton
单例设计模式:singleton 解决的问题: 确保程序在运行过程中,某个类的实例instance只有一份. 特点: 1 构造函数私有化 2 自己内部声明自己 3 提供一个public方法,负责实例化 ...
- java singleton(单例设计模式)
单例设计模式的主要作用是: 1.控制资源的使用,我们对资源使用线程同步来实现并发访问. 2.节约资源,我们对一个类只进行一个实例化进行全局的资源访问,节约了内存. 3.作为通信媒介,也是数据共享,可以 ...
- C++并发与多线程学习笔记--单例设计模式、共享数据分析
设计模式 共享数据分析 call_once 设计模式 开发程序中的一些特殊写法,这些写法和常规写法不一样,但是程序灵活,维护起来方便,别人接管起来,阅读代码的时候都会很痛苦.用设计模式理念写出来的代码 ...
- 牛客网Java刷题知识点之什么是单例模式?解决了什么问题?饿汉式单例(开发时常用)、懒汉式单例(面试时常用)、单例设计模式的内存图解
不多说,直接上干货! 什么是单例设计模式? 解决的问题:可以保证一个类在内存中的对象唯一性,必须对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性. 如何保证? 1.不允许其他程序用new ...
- GOF设计模式之1:单例设计模式
1.单例设计模式核心作用: 保证一个类只有一个实例,并且提供了访问该实例的全局访问点 2.常见应用场景: window的任务管理器 项目中读取配置文件一般也是一个单例模式 数据库连接池的设计也是采用单 ...
- Java面向对象 Main函数 静态的应用 单例设计模式
Java面向对象 Main函数 静态的应用与单例设计模式 知识概要 (1)Main函数的细解 (2)静态的应用,静态变量,静态代码块,静态函数 (3)单例设计模式 1.M ...
- JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制
JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是clas ...
- 死锁、Lock锁、等待唤醒机制、线程组、线程池、定时器、单例设计模式_DAY24
1:线程(理解) (1)死锁 概念: 同步中,多个线程使用多把锁之间存在等待的现象. 原因分析: a.线程1将锁1锁住,线程2将锁2锁住,而线程1要继续执行锁2中的代码,线程2要继续执行锁1中的代码, ...
- Java设计模式—单例设计模式(Singleton Pattern)全然解析
转载请注明出处:http://blog.csdn.net/dmk877/article/details/50311791 相信大家都知道设计模式,听的最多的也应该是单例设计模式,这种模式也是在开发中用 ...
随机推荐
- Ajax对数据的删除与查看
1.数据库找一张表: 颜色表2.主页面主页面的代码用到tbody:TBODY作用是:可以控制表格分行下载,从而提高下载速度.(网页的打开是先表格的的内容全部下载完毕后,才显示出来,分行下载可以先显示部 ...
- Oracle--索引视图序列等对象
---恢复内容开始--- 索引 与表类似,不仅需要在DD中保存索引的定义,还需要在表空间为它分配实际的存储空间. 将索引和对应的表分别存放在不同硬盘的不同表空间中能够提高查询的速度,因为Oracle能 ...
- 测开之路七十六:性能测试蓝图之html
<!-- 继承base模板 -->{% extends 'base.html' %} {% block script %} <!-- 从cdn引入ace edter的js --> ...
- elementUI 弹出框添加可自定义拖拽和拉伸功能,并处理边界问题
开发完后台管理系统的弹出框模块,被添加拖拽和拉伸功能,看了很多网上成熟的帖子引到项目里总有一点问题,下面是根据自己的需求实现的步骤: 首先在vue项目中创建一个js文件eg:dialog.js imp ...
- MySQL 基准测试
这是<高性能 MySQL(第三版)>第二章的读书笔记. 基准测试(benchmark)是针对系统的压力测试,用于掌握系统行为或重新系统的某个状态.sysbench 是常用的 MySQL 基 ...
- CentOS7 - 安装 MariaDB
1 安装并启动 MariaDB MariaDB 采用 Percona 的 XtraDB 存储引擎替代 MySQL 的 InnoDB,XtraDB 完全兼容 InnoDB. 1.1 安装 MySQL 与 ...
- EL表达式(三)自定义 EL 表达式
自定义EL函数(静态方法): 编写步骤: 1.编写一个Java类,提供一个静态方法 import java.util.List; public class GetLength { public sta ...
- Android 中三种启用线程的方法
在多线程编程这块,我们经常要使用Handler(处理),Thread(线程)和Runnable这三个类,那么他们之间的关系你是否弄清楚了呢? 首先说明Android的CPU分配的最小单元是线程,Han ...
- app本身性能测试简介
app 性能测试指标: 1.启动时间 2.内存占用量,内存警告次数 3.页面渲染时间,刷新帧率 4.网络请求时间.流量消耗 5.UI阻塞次数,不可操作时长,主线程阻塞超过400毫秒次数 6.耗电功率 ...
- Java 遍历某个目录
import java.io.File; import java.io.IOException; public class DirErgodic { public static void find(S ...