C++11并发与多线程笔记(7) 单例设计模式共享数据分析、解决,call_once

这篇具有很好参考价值的文章主要介绍了C++11并发与多线程笔记(7) 单例设计模式共享数据分析、解决,call_once。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.设计模式

  • 程序灵活,维护起来可能方便,用设计模式理念写出来的代码很晦涩,但是别人接管、阅读代码都会很痛苦
  • 老外应付特别大的项目时,把项目的开发经验、模块划分经验,总结整理成设计模式
  • 中国零几年设计模式刚开始火时,总喜欢拿一个设计模式往上套,导致一个小小的项目总要加几个设计模式,本末倒置
  • 设计模式有其独特的优点,要活学活用,不要深陷其中,生搬硬套

2.单例设计模式:

整个项目中,有某个或者某些特殊的类,只能创建一个属于该类的对象
单例类:只能生成一个对象。

# include<iostream>
using namespace std;
class MyClass {//单例类
private:
	MyClass(){}//私有化构造函数
	static MyClass* m_instance;//静态成员变量
public:
	static MyClass* getInstance() {//静态成员函数用于创建对象
		if (m_instance == NULL) {
			m_instance = new MyClass();
		}
		return m_instance;
	}
	void func() {
		cout << "测试" << endl;
	}
	
};
MyClass* MyClass::m_instance = NULL;//类内定义,类外初始化

int main() {
	//创建一个对象,返回该类(Myclass)对象的指针
	MyClass* p_a = MyClass::getInstance();
	p_a->func();//测试
}

如果觉得在单例模式new了一个对象,而没有自己delete掉,这样不合理。可以增加一个类中类CGarhuishou,new一个单例类时创建一个静态的CGarhuishou对象,这样在程序结束时会调用CGarhuishou的析构函数,释放掉new出来的单例对象。

# include<iostream>
using namespace std;
class MyClass {//单例类
private:
	MyClass(){}//私有化构造函数
	static MyClass* m_instance;//静态成员变量
public:
	static MyClass* getInstance() {//静态成员函数用于创建对象
		if (m_instance == NULL) {
			m_instance = new MyClass();
			static CGarhuishou cl; //释放对象
		}
		return m_instance;
	}

	class CGarhuishou {//类中套类,用来释放对象
	public:
		~CGarhuishou() {
			if (MyClass::m_instance) {
				delete MyClass::m_instance;
				MyClass::m_instance = NULL;
			}
		}
	};
	void func() {
		cout << "测试" << endl;
	}
	
};
MyClass* MyClass::m_instance = NULL;//类内定义,类外初始化

int main() {
	//创建一个对象,返回该类(Myclass)对象的指针
	MyClass* p_a = MyClass::getInstance();
	p_a->func();//测试
}

3.单例设计模式共享数据分析、解决

面临问题:需要在自己创建的线程(而不是主线程)中来创建单例类的对象,这种线程可能不止一个。我们可能面临getInstance()这种成员函数需要互斥。
解决方法:可以在
加锁前判断m_instance是否为空
,否则每次调用MyClass::getInstance()都要加锁,十分影响效率。

# include<iostream>
# include<thread>
#include<mutex>
using namespace std;
mutex mutex1;
class MyClass {//单例类
private:
	MyClass(){}//私有化构造函数
	static MyClass* m_instance;//静态成员变量
public:
	static MyClass* getInstance() {
		//双重锁定 提高效率
		if (m_instance == NULL) {
			unique_lock<mutex> myMutex(mutex1);//单独加此代码,每一次判断创建新对象,都要加锁
			if (m_instance == NULL) {
				m_instance = new MyClass();
				static CGarhuishou cl;
			}
		}
		return m_instance;
	}

	class CGarhuishou {//类中套类,用来释放对象
	public:
		~CGarhuishou() {
			if (MyClass::m_instance) {
				delete MyClass::m_instance;
				MyClass::m_instance = NULL;
			}
		}
	};
	void func() {
		cout << "测试" << endl;
	}
};
MyClass* MyClass::m_instance = NULL;//类内定义,类外初始化

//线程入口函数
void mythread() {
	cout << "myPrint线程开始执行了 " << endl;
	MyClass* p_a = MyClass::getInstance();
	cout << "myPrint线程结束执行了"  << endl;
}
int main() {
	thread myobj1(mythread);
	thread myobj2(mythread);
	myobj1.join();
	myobj2.join();
}

4.std::call_once():

函数模板,该函数的第一个参数标记第二个参数是一个函数名(如a())。
功能:能够保证函数a()只被调用一次。具备互斥量的能力,而且比互斥量消耗的资源更少,更高效。

  • call_once()需要与一个标记结合使用,这个标记为std::once_flag;其实once_flag是一个结构,call_once()就是通过标记来决定函数是否执行,调用成功后,就把标记设置为一种已调用状态

  • 多个线程同时执行时,使用call_once(),一个线程会等待另一个线程先执行。文章来源地址https://www.toymoban.com/news/detail-657307.html

# include<iostream>
# include<thread>
#include<mutex>
using namespace std;
once_flag g_flag;//标记来决定函数是否执行

class MyClass {//单例类
private:
	MyClass() {}//私有化构造函数
	static MyClass* m_instance;//静态成员变量
public:
	//用于call_once函数的第二个参数,保证其只被调用一次
	static void CreateInstance() {
		m_instance = new MyClass;
		static CGarhuishou cl;
	}
	//两个线程同时执行到这里,其中一个线程要等另外一个线程执行完毕
	static MyClass* getInstance() {
		call_once(g_flag,CreateInstance);
		return m_instance;
	}

	class CGarhuishou {//类中套类,用来释放对象
	public:
		~CGarhuishou() {
			if (MyClass::m_instance) {
				delete MyClass::m_instance;
				MyClass::m_instance = NULL;
			}
		}
	};
	void func() {
		cout << "测试" << endl;
	}
};
MyClass* MyClass::m_instance = NULL;//类内定义,类外初始化

//线程入口函数
void mythread() {
	cout << "myPrint线程开始执行了 " << endl;
	MyClass* p_a = MyClass::getInstance();
	cout << "myPrint线程结束执行了"  << endl;
}
int main() {
	thread myobj1(mythread);
	thread myobj2(mythread);
	myobj1.join();
	myobj2.join();
}

到了这里,关于C++11并发与多线程笔记(7) 单例设计模式共享数据分析、解决,call_once的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【设计模式】详解单例设计模式(包含并发、JVM)

    在软件开发中,经常需要某些类 只能有唯一的实例 ,比如数据库连接。如何才能保证整个应用中只有一个唯一实例?如果靠人为制定的协定来约束,显然不能很好的保证这一点。如果要从 语法上约束 ,在面向对象里面,什么地方能够约束实例的创建? 显然,只有 构造函数

    2024年02月15日
    浏览(26)
  • 设计模式(单例模式,工厂模式),线程池

    目录 什么是设计模式? 单例模式 饿汉模式 懒汉模式 工厂模式 线程池 线程池种类 ThreadPoolExcutor的构造方法: 手动实现一个线程池  计算机行业程序员水平层次不齐,为了 让所有人都能够写出规范的代码, 于是就有了设计模式, 针对一些典型的场景,给出一些典型的解决方案 单例

    2024年02月11日
    浏览(31)
  • C++11并发与多线程笔记(9) async、future、packaged_task、promise

    std::async : 是一个函数模板,用来启动一个异步任务,启动起来一个异步任务之后,它返回一个std::future对象,这个对象是个类模板。 什么叫“ 启动一个异步任务 ”?就是自动创建一个线程,并开始执行对应的线程入口函数,它返回一个std::future对象,这个std::future对象中就

    2024年02月12日
    浏览(28)
  • C++11并发与多线程笔记(10) future其他成员函数、shared_future、atomic

    status = result.wait_for(std::chrono::seconds(几秒)); 卡住当前流程,等待std::async()的异步任务运 行一段时间,然后返回其状态std::future_status 。如果std::async()的参数是std::launch::deferred(延迟执行),则不会卡住主流程。 std::future_status是枚举类型,表示异步任务的执行状态。类型的取值

    2024年02月12日
    浏览(30)
  • 设计模式3:单例模式:静态内部类模式是怎么保证单例且线程安全的?

    上篇文章:设计模式3:单例模式:静态内部类单例模式简单测试了静态内部类单例模式,确实只生成了一个实例。我们继续深入理解。 静态变量什么时候被初始化? 这行代码 private static Manager instance = new Manager(); 什么时候执行? 编译期间将.java文件转为.class文件,运行期间

    2024年02月12日
    浏览(33)
  • 设计模式——C++11实现单例模式(饿汉模式、懒汉模式),与单例的进程

    本文将介绍单例模式,使用C++11实现多个版本的单例模式,分析各自的优缺点。最后提及如何实现一个单例的进程。 单例模式属于创建型模式,提供了一种创建对象的方式。 单例模式确保一个类只有一个实例。通过一个类统一地访问这个实例。 思想:将构造函数设置为私有

    2024年02月09日
    浏览(36)
  • 【Java中23种设计模式-单例模式2--懒汉式2线程安全】

    加油,新时代打工人! 简单粗暴,学习Java设计模式。 23种设计模式定义介绍 Java中23种设计模式-单例模式 Java中23种设计模式-单例模式2–懒汉式线程不安全 通过运行结果看,两个线程的地址值是相同的,说明内存空间里,创建了一个对象。

    2024年02月20日
    浏览(37)
  • 【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式

    🍎 个人博客: 个人主页 🏆 个人专栏: JAVA ⛳️   功不唐捐,玉汝于成 目录 前言 正文 懒汉式(Lazy Initialization): 双重检查锁定(Double-Checked Locking): 结语 我的其他博客 在软件设计中,单例设计模式是一种重要的设计思想,它确保了一个类只有一个实例,并提供了一

    2024年01月15日
    浏览(41)
  • 【Linux】简单线程池的设计与实现 -- 单例模式

    线程池: 一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而 线程池维护着多个线程,等待着监督管理者分配可并发执行的任务 。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。

    2024年02月12日
    浏览(31)
  • 设计模式 : 单例模式笔记

    一个类 只能创建一个对象 ,这样的类的设计模式就称为单例模式,该模式保证 系统中 该类 只能有一个实例 (并且 父子进程共享 ),一个很典型的单例类就是C++STL的内存池 C++单例模式的基本设计思路: 私有化 构造函数 ,删除默认的 拷贝构造函数 和 赋值运算符重载 防止对象被直

    2024年02月12日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包