C++11第五弹:线程库 | 互斥锁 | 原子操作

news2024/9/19 21:57:29

在这里插入图片描述

🌈个人主页: 南桥几晴秋
🌈C++专栏: 南桥谈C++
🌈C语言专栏: C语言学习系列
🌈Linux学习专栏: 南桥谈Linux
🌈数据结构学习专栏: 数据结构杂谈
🌈数据库学习专栏: 南桥谈MySQL
🌈Qt学习专栏: 南桥谈Qt
🌈菜鸡代码练习: 练习随想记录
🌈git学习: 南桥谈Git

🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈
本科在读菜鸡一枚,指出问题及时改正

文章目录

  • thread类的简单介绍
    • 线程函数为函数指针
    • 线程函数为lambda表达式
    • 创建多个线程
  • 互斥锁
    • lock_guard
    • unique_lock
  • 原子操作
  • 条件变量
    • 两个线程交替打印,一个打印奇数,一个打印偶数

thread类的简单介绍

在C++11之前,涉及到多线程问题,都是和平台相关的,比如windows和linux下各有自己的接口,这使得代码的可移植性比较差。C++11中最重要的特性就是对线程进行支持了,使得C++在并行编程时不需要依赖第三方库,而且在原子操作中还引入了原子类的概念。要使用标准库中的线程,必须包含< thread >头文件。

线程库文档

函数名功能
thread()构造一个线程对象,没有关联任何线程函数,即没有启动任何线程
thread(fn,args1, args2,…)构造一个线程对象,并关联线程函数fn,args1,args2,…为线程函数参数导管
get_id()获取线程id
jionable()线程是否还在执行,joinable代表的是一个正在执行中的线程
jion()该函数调用后会阻塞住线程,当该线程结束后,主线程继续执行
detach()在创建线程对象后马上调用,用于把被创建线程与线程对象分离开,分离的线程变为后台线程,创建的线程的"死活"就与主线程无关

线程函数为函数指针

void Printf(int n,int i)
{
	for (; i < n; i++)
	{
		cout << i << endl;
	}
	cout << endl;
}

int main()
{
	thread t1(Printf, 100, 0);
	thread t2(Printf, 200, 100);
	
	cout << t1.get_id() << endl;

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

	cout << this_thread::get_id() << endl;
	return 0;
}

上述代码实现两个线程并发打印。

对于访问同一个变量,会出现线程安全问题,因此需要加锁,加锁需要包含一个<mutex>头文件。对于线程的互斥,在线程ID与互斥中有详细解释,本文不再细谈。

int x;
mutex mtx;

void Printf(int n)
{
	mtx.lock();
	for (int i = 0; i < n; i++)
	{
		x++;
	}
	mtx.unlock();
}

int main()
{
	thread t1(Printf, 10000);
	thread t2(Printf, 20000);

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

	cout << x << endl;

	return 0;
}

线程中传参问题:多个线程访问和修改同一个 x 变量,并使用相同的 mutex 对象来确保线程安全。std::ref 使得 x mtx 被作为引用传递,这样线程函数 Printf 就能直接修改主线程中的 xmtx

void Printf(int n, int& rx, mutex& rmtx)
{
	rmtx.lock();
	for (int i = 0; i < n; i++)
	{
		rx++;
	}
	rmtx.unlock();
}

int main()
{
	int x = 0;
	mutex mtx;

	thread t1(Printf, 10000, ref(x), ref(mtx));
	thread t2(Printf, 20000, ref(x), ref(mtx));



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

	cout << x << endl;

	return 0;
}

线程函数为lambda表达式

[&] 是 lambda 表达式的捕获列表,表示 lambda 函数可以捕获外部作用域的所有变量的引用。这意味着在 lambda 表达式中可以直接访问和修改主线程中的变量,而不需要将它们作为参数传递。

int main()
{
	int x = 0;
	mutex mtx;

	thread t1([&] {
		mtx.lock();
		for (int i = 0; i < 10000; i++)
		{
			++x;
		}
		mtx.unlock();
		});
	thread t2([&] {
		mtx.lock();
		for (int i = 0; i < 20000; i++)
		{
			++x;
		}
		mtx.unlock();
		});

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

	cout << x << endl;

	return 0;
}

创建多个线程

int main()
{
	vector<thread> vthd;
	int n;
	cin >> n;
	vthd.resize(n);

	int x = 0;
	mutex mtx;
	auto func = [&](int n) {
		mtx.lock();
		for (size_t i = 0; i < n; i++)
		{
			++x;
		}
		mtx.unlock();
	};

	for (auto& thd : vthd)
	{
		//移动赋值
		thd = thread(func, 10000);
	}

	for (auto& thd : vthd)
	{
		thd.join();
	}

	cout << x << endl;

	return 0;
}

在这里插入图片描述

互斥锁

在这里插入图片描述

互斥锁文档

lock_guard

在使用lockunlock时,如果中间抛异常,那么就无法解锁,就是死锁。因此设计了rna的概念,有了lockguard函数。

在库中的lock_guard仅支持构造和析构函数。

在这里插入图片描述

模拟实现lockguard

class LockGuard
{
public:
	LockGuard(mutex& mtx)
		:_mtx(mtx)
	{
		_mtx.lock();
	}

	~LockGuard()
	{
		_mtx.unlock();
	}

private:
	mutex& _mtx;
};

LockGuard lock(mtx)构造一个LockGuard的对象,会有一个引用将mutex保存起来,获取锁,将锁锁住,除了作用域后,会调用析构函数,解锁。无论是正常结束还是抛异常,生命周期都会结束,都会调用析构函数。
在这里插入图片描述

如果有两个循环,只想锁住第一个循环,不锁第二个循环。在使用lockunlock时可以控制范围,那么LockGuard如何解决?
在这里插入图片描述

解决方法:增加一个局部域,可以显示控制对象的生命周期:

在这里插入图片描述

unique_lock

在这里插入图片描述

支持手动加锁解锁,相比于lock_guard功能更丰富些。

原子操作

多线程最主要的问题是共享数据带来的问题(即线程安全)。如果共享数据都是只读的,那么没问题,因为只读操作不会影响到数据,更不会涉及对数据的修改,所以所有线程都会获得同样的数据。但是,当一个或多个线程要修改共享数据时,就会产生很多潜在的麻烦。

atomic文档

atomic是一个类,支持原子的加减或者异或,在使用时需要<atomic>头文件

在这里插入图片描述

所支持的类型:

在这里插入图片描述

class LockGuard
{
public:
	LockGuard(mutex& mtx)
		:_mtx(mtx)
	{
		_mtx.lock();
	}

	~LockGuard()
	{
		_mtx.unlock();
	}

private:
	mutex& _mtx;
};

int main()
{
	vector<thread> vthd;
	int n;
	cin >> n;
	vthd.resize(n);

	//atomic<int> x = 0;
	atomic<int> x{ 0 };
	mutex mtx;
	auto func = [&](int n) {
		//mtx.lock();
		{
			LockGuard lock(mtx);
			for (size_t i = 0; i < n; i++)
			{
				++x;
			}
			//mtx.unlock();
		}
	};

	for (auto& thd : vthd)
	{
		//移动赋值
		thd = thread(func, 10000);
	}

	for (auto& thd : vthd)
	{
		thd.join();
	}

	cout << x << endl;

	return 0;
}

在这里插入图片描述

条件变量

阅读文档

条件变量(std::condition_variable)是用于线程间同步的工具,它可以使一个线程等待某个条件的发生,而另一个线程则在条件发生时通知等待的线程。条件变量通常与互斥锁(std::mutex)一起使用,以确保线程在等待或通知条件时不会引发数据竞争。

condition_variableLinux posix的条件变量并没有什么大的区别,主要还是面向对象实现的。

Linux的条件变量可阅读博客:线程同步-条件变量

两个线程交替打印,一个打印奇数,一个打印偶数

void two_thread_print()
{
	std::mutex mtx;
	condition_variable c;
	int n = 100;
	bool flag = true;

	thread t1([&]() {
		int i = 0;
		while (i < n)
		{
			unique_lock<mutex> lock(mtx);
			c.wait(lock, [&]()->bool {return flag; });
			cout << i << endl;
			flag = false;
			i += 2; // 偶数
			c.notify_one();
		}
		});

	thread t2([&]() {
		int j = 1;
		while (j < n)
		{
			unique_lock<mutex> lock(mtx);
			c.wait(lock, [&]()->bool {return !flag; });
			cout << j << endl;
			j += 2; // 奇数
			flag = true;
			c.notify_one();
		}
		});

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

int main()
{
	two_thread_print();
	return 0;
}

在这里插入图片描述

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

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

相关文章

蓝牙耳机是入耳式的好还是开放式的好?2024开放式耳机推荐

个人推荐入开放式耳机&#xff0c;戴起来更舒服&#xff0c;主要有以下几方面原因&#xff1a; 减少对耳部的压迫&#xff1a; 不入耳设计&#xff1a;开放式耳机通常不需要插入耳道&#xff0c;避免了对耳道的直接压迫。入耳式耳机的耳塞长时间塞在耳道内&#xff0c;会对耳…

Linux基础---07文件传输

Linux文件传输地图如下&#xff0c;先选取你所需的场景&#xff0c;若你是需要Linux和Linux之间传输文件就查看SCP工具即可。 一.下载网站文件 前提是有网&#xff1a; 检查网络是否畅通命令&#xff1a;ping www.baidu.com&#xff0c;若有持续的返回值就说明网络畅通。Ctr…

前端基础知识(HTML+CSS+JavaScript)

文章目录 一、HTML1.1 HTML 基础&#xff1a;1.1.1 HTML 的概念&#xff1a;1.1.2 认识 HTML 标签&#xff1a;1.1.3 HTML 文件基本结构&#xff1a;1.1.4 标签层次结构&#xff1a; 1.2 HTML 快速入门&#xff1a;1.3 HTML常见标签&#xff1a;1.3.1 标题标签&#xff1a;h1-h…

数据结构-2.顺序表

1.线性表 线性是n个具有相同特性的数据元素的有限序列. 线性表是一种在实际中广泛使用的数据结构,常见的线性表有: 顺序表 , 链表 , 栈 , 队列... 线性表在逻辑上是线性结构, 也就是连续的一条直线 . 但是在物理结构上并不是连续的, 线性表在物理上存储时, 通常以数组和链式结…

5-----RYZ维修工具 操作界面预览与功能操作解析 刷机 解锁 修复参数等等

以上是工具选项功能的界面预览 。通过预览可以看到很多功能选项。此类工具涵盖了很多操作区域。需要根据自己机型的实际需求来操作。根据开发者的描述。此工具有一下功能。包含mtk刷机 分区修复。9008刷机 备份基带efs等等。 高通操作区域 高通修复串码 高通修改写入基带qc…

石化盈科PMO总经理任志婷受邀为第四届中国项目经理大会演讲嘉宾

全国项目经理专业人士年度盛会 石化盈科信息技术有限责任公司运营管理部总经理兼PMO总经理任志婷女士受邀为PMO评论主办的全国项目经理专业人士年度盛会——2024第四届中国项目经理大会演讲嘉宾&#xff0c;演讲议题为“激活关键的少数派——项目经理培养体系的设计实践”。大会…

无人机视角下落水救援检测数据集

无人机视角下落水救援检测数据集&#xff0c;利用无人机快速搜索落水者对增加受害者的生存机会至关重要&#xff0c;该数据集共收集12万帧视频图像&#xff0c;涵盖无人机高度从10m-60m高度&#xff0c;检测包括落水者&#xff08;11万标注量&#xff09;、流木&#xff08;900…

TCP/IP - ICMP

目录 1. 帧格式2. ICMPv4消息类型(Type = 0,Code = 0)回送应答 /(Type = 8,Code = 0)回送请求(Type = 3)目标不可达(Type = 5)重定向(Type = 11)ICMP超时(Type = 12)参数3. ICMPv6消息类型回见TCP/IP 对ICMP协议作介绍 ICMP(Internet Control Message Protocol…

什么是快充协议,最常见的快充协议有哪些

什么是快充协议 随着手机快充的出现大家都知道快充技术但很多人确不知道快充协议&#xff0c;在快充技术里快充协议是必不可少的&#xff0c;那么今天我们就来探讨一下什么是快充协议&#xff1f; 快充协议是一种通过提高充电效率来缩短设备充电时间的电池充电技术。它通过在充…

商淘云九周年 分账系统助力企业合规发展

从2015到2024年&#xff0c;商淘云电商服务品牌已走过整整九个春秋。这九年&#xff0c;是商淘云不断发展壮大&#xff0c;深化品牌建设服务&#xff0c;并取得显著成效的九年&#xff0c;也是见证中国电商迅速崛起的九年。我们回顾九年的风雨历程&#xff0c;感受到企业的成长…

Python计算机视觉 第9章-图像分割

Python计算机视觉 第9章-图像分割 图像分割是将一幅图像分割成有意义区域的过程。区域可以是图像的前景与背景或图像中一些单独的对象。这些区域可以利用一些诸如颜色、边界或近邻相似性等特征进行构建。 9.1 图割&#xff08;Graph Cut&#xff09; 图割&#xff08;Graph…

SOMEIP_ETS_111: SD_Empty_Entries_Array

测试目的&#xff1a; 验证DUT能够忽略声明了条目数组长度为零的SubscribeEventgroup消息。 描述 本测试用例旨在确保DUT在接收到一个Entries数组长度为零的SubscribeEventgroup消息时&#xff0c;能够正确地忽略该消息&#xff0c;不对其进行解释或响应。 测试拓扑&#x…

【机器学习-监督学习】朴素贝叶斯

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈Python机器学习 ⌋ ⌋ ⌋ 机器学习是一门人工智能的分支学科&#xff0c;通过算法和模型让计算机从数据中学习&#xff0c;进行模型训练和优化&#xff0c;做出预测、分类和决策支持。Python成为机器学习的首选语言&#xff0c;…

数据中台建设(七)——数据体系建设

数据体系建设 数据中台是企业数据汇集地&#xff0c;但并不是简单的数据堆积&#xff0c;而是进行分层建模&#xff0c;数据体系建设最终呈现一套完整、规范、准确的数据。数据体系建设就是大数据中数据仓库建设。如下图&#xff1a; 贴源数据层ODS(Operational Data Store)…

python的数据类型详解

python基础 认识python基本类型python的注释风格有三种&#xff08;也可以说是两种&#xff09;python的对齐方式python的多行语句折断字符串类型的“计算”列表的常见用法元组的常见用法集合set的常见用法字典的常见用法bytes类型python的输入输出python中的引用 认识python基…

基于环境音频和振动数据的人类活动识别

这篇论文的标题是《Recognition of human activities based on ambient audio and vibration data》&#xff0c;作者是 Marcel Koch 等人&#xff0c;发表在 IEEE Access 期刊上。论文提出了一种基于环境音频和振动数据的分布式多传感器系统&#xff0c;用于识别人类活动。以下…

窗口框架frame(HTML前端)

一.窗口框架 作用&#xff1a;将网页分割为多个HTML页面&#xff0c;即将窗口分为多个小窗口&#xff0c;每个小窗口可以显示不同的页面&#xff0c;但是在浏览器中是一个完整的页面 基本语法 <frameset cols"" row""></frameset><frame…

好的知识竞赛策划公司哪里去找

活动不管多大&#xff0c;都败在策划公司手中&#xff01;要找到好的策划公司&#xff0c;可以考虑以下几个途径&#xff1a; 1.搜索引擎&#xff1a; 通过搜索引擎&#xff0c;可以找到行业内有实力的优秀策划公司。尽管有些公司是打广告&#xff0c;那总比没钱打广告的公司…

Codes 开源研发项目管理平台——敏捷测试管理创新解决方案

前言 Codes 是国内首款重新定义 SaaS 模式的开源项目管理平台&#xff0c;支持云端认证、本地部署、全部功能开放&#xff0c;并且对30人以下团队免费。它通过整合迭代、看板、度量和自动化等功能&#xff0c;简化测试协同工作&#xff0c;使敏捷测试更易于实施。并提供低成本的…