C++多线程2(复习向)

news2024/11/19 19:42:19

lock_guard

lock_guard是C++中提供的对互斥锁有关操作的高级接口,可对互斥锁进行自动上锁和解锁,多用于作为局部变量。(在对象创建时,构造函数中自动为传入的互斥锁对象上锁,局部变量被系统回收时,其析构函数自动对互斥锁对象进行解锁)
代码如下

#include <iostream>
#include <thread>
#include<mutex>
using namespace std;
//共享变量
int a = 0;
//定义信号量mutex
mutex mtx;
void add()
{
	for (int i = 0; i < 100; i++)
	{
		//等价于mtx.lock + mtx.unlock
		lock_guard<mutex> lg(mtx);
		a++;
	}
		
}

int main()
{
	thread thread1(add);
	thread thread2(add);

	thread1.join();
	thread2.join();
	cout << "共享变量a = " << a << endl;
	return 0;
}

在这里插入图片描述

unique_lock

unique_lock是比lock_guard更加强大的对互斥锁管理的接口,除了对互斥锁的自动上锁和解锁,还有延时上锁等功能,因此使用频率更高,开发中更多地使用这个接口。

void add2()
{
	for (int i = 0; i < 100; i++)
	{
	//unique_lock也可以进行自动上锁和解锁与lock_guard等效
		unique_lock<mutex> ul(mtx);
		a++;
	}
}

int main()
{
	thread thread1(add2);
	thread thread2(add2);

	thread1.join();
	thread2.join();
	cout << "共享变量a = " << a << endl;
	return 0;
}
//延迟锁,mutex不允许延迟操作
timed_mutex t_mtx;
void adde()
{
	for (int i = 0; i < 100; i++)
	{
		unique_lock<timed_mutex> ul(t_mtx, defer_lock);//加上后续的defer_lock代表不要自动加锁
		//		ul.try_lock_until() 很少使用,无法获取互斥锁就阻塞到某个时间点,过点则返回
		bool flag = ul.try_lock_for(chrono::seconds(5)); //若此时无法获取互斥锁,则只会阻塞5秒,拿到锁返回true,否则返回false
		if (flag)
			a++;
	}
}

int main()
{
	thread thread1(add2);
	thread thread2(add2);

	thread1.join();
	thread2.join();
	cout << "共享变量a = " << a << endl;
	return 0;
}

单例模式与call_once

我们在使用类时,有些类只需要创建一个对象即可满足我们的使用需求,这时我们可以使用单例模式来设计这个类
单例模式下
无参构造要放在私有域下,且需要禁用拷贝构造和重载=运算符

饿汉模式

饿汉模式,一开始就把对象创建好,即为饿汉模式

class Log {
private:
	Log(){}//单例模式下,构造函数放在private域下
	Log(const Log& l) = delete;
	Log& operator=(const Log& log) = delete;
public:
	static Log& GetInstanceHungry()
	{
		static Log log;//静态作用域下只有一个log对象,而提前创建好对象为饿汉模式
		return log;
	}
	void printLog(string s)
	{
		cout << s << endl;
	}

};

懒汉模式

需要使用时才将对象创建好为懒汉模式

//once_flag类型得放到类外,否则报错
static once_flag flag;
class Log2 {
private:
	Log2(){}
	Log2(const Log2& l) = delete;
	Log2& operator=(const Log2& log) = delete;
public:
	//需要用到再创建对象就是懒汉模式
	static Log2& GetInstanceLazy() {
		static Log2* l = nullptr;
		//call_once当多个线程都要调用获取实例的的函数时,保证只有一个线程执行call_once
		call_once(flag, [&]() {
			if (l == nullptr)
				l = new Log2;
			});
		return *l;
	}
	void printLog(string s)
	{
		cout << s << endl;
	}
};

call_once与单例模式

以懒汉模式为例,当多个线程同时打印输出时,有可能产生一种情况两者同时进入获取对象的函数,则此时静态对象会被new两次,这与我们单例模式只需要创建一个对象的设计思路就不符合了
而C++提供的call_once函数则保证了,在多个线程访问创建实例的函数时,只有一个线程去创建这个实例,因此有且只有一个实例
而饿汉不存在资源竞争关系,因为一开始就分配好了,且只有一次

#include <iostream>
#include <thread>
#include <mutex>
#include <string>
using namespace std;

//单例模式,只需要创建一个对象的类,如日志类
//单例模式下又有饿汉模式和懒汉模式
class Log {
private:
	Log(){}//单例模式下,构造函数放在private域下
	Log(const Log& l) = delete;
	Log& operator=(const Log& log) = delete;
public:
	static Log& GetInstanceHungry()
	{
		static Log log;//静态作用域下只有一个log对象,而提前创建好对象为饿汉模式
		return log;
	}
	void printLog(string s)
	{
		cout << s << endl;
	}

};
//once_flag类型得放到类外,否则报错
static once_flag flag;
class Log2 {
private:
	Log2(){}
	Log2(const Log2& l) = delete;
	Log2& operator=(const Log2& log) = delete;
public:
	//需要用到再创建对象就是懒汉模式
	static Log2& GetInstanceLazy() {
		static Log2* l = nullptr;
		//call_once当多个线程都要调用获取实例的的函数时,保证只有一个线程执行call_once
		call_once(flag, [&]() {
			if (l == nullptr)
				l = new Log2;
			});
		return *l;
	}
	void printLog(string s)
	{
		cout << s << endl;
	}
};
//饿汉模式
void test01()
{
	Log::GetInstanceHungry().printLog("饿汉模式的Hello World");
}
//懒汉模式
void test02()
{
	Log2::GetInstanceLazy().printLog("懒汉模式的Hello World2");
}
//call_once 使用懒汉的Log2
void printString()
{
	Log2::GetInstanceLazy().printLog("call_once的Hello World2");
}
int main()
{
	test01();
	test02();

	thread t1(printString);
	thread t2(printString);

	t1.join();
	t2.join();

	return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1417261.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

消失的数字(c语言多种解法)

题目 该题目取自力扣&#xff08;LeetCode&#xff09;面试题 17.04. 消失的数字 该题目主要考察时间复杂度的把握&#xff0c;题目如下&#xff1a; 数组nums包含从0到n的所有整数&#xff0c;但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗&a…

幻兽帕鲁服务器出租,腾讯云PK阿里云怎么收费?

幻兽帕鲁服务器价格多少钱&#xff1f;4核16G服务器Palworld官方推荐配置&#xff0c;阿里云4核16G服务器32元1个月、96元3个月&#xff0c;腾讯云换手帕服务器服务器4核16G14M带宽66元一个月、277元3个月&#xff0c;8核32G22M配置115元1个月、345元3个月&#xff0c;16核64G3…

【MySQL】补充和navicat的一些简单使用

文章目录 前言在这里插入图片描述 事情起因因为这个articlecount的c是小写了&#xff0c;我想改成大写 一、修改二、navicat的使用步骤1.连接2.建库&#xff0c;建表 三.填写数据总结 前言 事情起因因为这个articlecount的c是小写了&#xff0c;我想改成大写 提示&#xff1a;…

[css] 让文字进行竖着 分散对齐

.demo2 {width: 60px;background-color: aqua;height: 200px;display: grid;place-items: center;}参考&#xff1a; css 让文字进行竖着书写&#xff0c; 附带个小知识&#xff0c;行内块元素添加文字之后底部对不齐的问题

系统架构15 - 软件工程(3)

软件过程模型 瀑布模型特点缺点 原型化模型特点两个阶段不同类型注意 螺旋模型V 模型特点 增量模型特点 喷泉模型基于构件的开发模型(CBSD)形式化方法模型敏捷模型特点“适应性” (adaptive) 而非“预设性” (predictive)“面向人的” (People-oriented) 而非“面向过程的” (P…

动态规划算法题刷题笔记

首先看动态规划的三要素&#xff1a;重叠子问题、最优子结构和状态转移方程。 重叠子问题&#xff1a;存在大量的重复计算 最优子结构&#xff1a; 状态转移方程&#xff1a;当前状态转移成以前的状态 动态规划的解题步骤主要有&#xff1a; 确定 dp 数组以及下标的含义状…

【Redis】Redis有哪些适合的场景

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Redis ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 &#xff08;1&#xff09;会话缓存&#xff08;Session Cache&#xff09; &#xff08;2&#xff09;全页缓存&#xff08;FPC…

JetpackCompose 之 状态学习

1.无状态组件 1.1导入依赖 implementation("androidx.core:core-ktx:1.9.0")implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")implementation("androidx.activity:activity-compose:1.7.0")implementation(platform("an…

MyBatis详解(3)-- 动态代理及映射器

MyBatis详解&#xff08;3&#xff09; mybatis 动态代理动态代理的规范selectOne和selectListnamespace mybatis映射器映射器的引入&#xff1a; 映射器的组成select 元素结构&#xff1a;单个参数传递多个参数传递 insert 元素结构主键回填&#xff1a;自定义主键生成规则 u …

CSS 双色拼接按钮效果

<template><view class="sss"><button> <!-- 按钮 --><view class="span"> 按钮 </view> <!-- 按钮文本 --></button></view></template><script></script><style>body {b…

JUC-ReentrantLock,ReentrantReadWriteLock,StampedLock

1. 概述 前面介绍过了synchronized关键字作用的锁升级过程 无锁->偏向锁->轻量锁->重锁 下面再介绍实现Lock接口的锁的升级过程 无锁->独占锁&#xff08;ReentrantLock&#xff0c;Synchronized&#xff09;->读写锁(ReentranReadWriteLock)->邮戳锁(Stamp…

app逆向-apktool逆向工具安装使用

文章目录 一、前言二、安装三、执行 一、前言 apktool是一个能够解析和分析安卓应用文件&#xff08;APK&#xff09;的工具&#xff0c;帮助了解应用程序的内部结构和功能。 二、安装 window版本 下载地址&#xff1a;版本2.9.3&#xff0c;并将下载的 jar 重命名为apktoo…

【缓存周总结】Redis缓存的使用以及数据安全的处理

前言 Redis非关系型数据库已经是很常见的工具了&#xff0c;项目中用到的也很多&#xff0c;这篇文章系统的分析下使用过程中可能会遇到的问题 一、缓存 缓存是数据交换的缓冲区&#xff0c;是存贮数据的临时地方&#xff0c;一般读写性能较高。 我们项目中引用的Redis目的就是…

SPI:JDK 与 SpringBoot

浅谈Java SPI原理与其在JDBC、Flink中的应用 API&#xff1a;由被调方提供的实现了某个完整功能的接口&#xff0c;主调方直接调用该接口来享用该功能&#xff0c;而无需关注该接口的具体实现。比如使用 JDK 的 InputStream#read 从文件系统中读取数据。 SPI&#xff1a;被调方…

DOM 型 XSS 攻击演示(附链接)

一、介绍 DOM&#xff08;Document Object Model&#xff09;型 XSS&#xff08;Cross-Site Scripting&#xff09;攻击是一种 Web 应用程序中的安全漏洞&#xff0c;其特点是攻击者成功地注入了恶意脚本&#xff0c;这些脚本在用户的浏览器中执行&#xff0c;从而导致恶意行为…

DETR解读,将Transformer带入CV

论文出处 [2005.12872] End-to-End Object Detection with Transformers (arxiv.org) 一个前置知识 匈牙利算法&#xff1a;来源于二部图匹配&#xff0c;计算最小或最大匹配 算法操作&#xff1a;在n*n的矩阵中 减去行列最小值&#xff0c;更新矩阵&#xff08;此时行或者…

C# RichTextBox常用属性、方法学习1

1 字体 Font font1 new Font("宋体", 18); richTextBox1.Font font1; Font font2 new Font("宋体", 10, FontStyle.Underline); richTextBox1.SelectionFont font2; 定义字体&#xff0c;可以带2个参数&#…

代码随想录刷题笔记-Day13

1. 二叉树的层序遍历 102. 二叉树的层序遍历https://leetcode.cn/problems/binary-tree-level-order-traversal/层次遍历依靠队列的先进先出特点实现。 解题思路 层序遍历的本质就是对每一个pop出来的处理节点&#xff0c;处理后把他的左右节点放进去。 对于每一层来说&…

菱形打印和十进制ip转二进制

1.菱形打印 用for循环 #!/bin/bashread -p "请输入菱形的大小&#xff1a;" num #打印向上的等腰三角形 for ((i1;i<num;i)) dofor ((jnum-1;j>i;j--))doecho -n " " #打印的是前面的空格donefor ((k1;k<2*i-1;k))doecho -n "*" #打印…

【stm32】hal库学习笔记-FSMC连接TFT_LCD

【stm32】hal库学习笔记-FSMC连接TFT LCD 触摸屏结构与原理 LCD模块接口原理图 LCD 接口连接在 FSMC 总线上面&#xff0c;图中的 T_MISO/T_MOSI/T_PEN/T_SCK/T_CS 连接在 MCU 的 PB2/PF11/PB1/PB0/PC13 上&#xff0c;这些信号用来实现对液晶触摸屏的控制&#xff08;支持电阻…