C++关于线程的一些操作

news2024/9/23 11:19:03

线程创建和接收

 

 std::this_thread::get_id()获取当前线程的线程ID

std::this_thread::yield()让步结束当前线程的时间片

int main()
{
	vector<thread> threads(2);
	threads[0] = thread([]() {cout << this_thread::get_id() << endl;});
	threads[1] = thread([]() {cout << this_thread::get_id() << endl;});
	thread thread3([]() {cout << this_thread::get_id() << endl;});
	for (auto& e : threads)
	{
		e.join();
	}
	thread3.join();
	return 0;
}
//14136
//15844
//16272

原子操作

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

int main()
{
	int val = 0;
	vector<thread> threads(2);
	threads[0] = thread([&](int n) {
		for (int i = 0; i < n; ++i)
		{
			++val;
		}}, 100000);
	threads[1] = thread([&](int n) {
		for (int i = 0; i < n; ++i)
		{
			++val;
		}}, 200000);
	for (auto& e : threads)
	{
		e.join();
	}
	cout << val << endl;
	return 0;
}

这个程序跑出来的结果不确定,有时候会比较小,这都是由于多线程导致的数据不一致。

虽然加锁可以解决,但是加锁有一个缺陷就是:只要一个线程在对sum++时,其他线程就会被阻 塞,会影响程序运行的效率,而且锁如果控制不好,还容易造成死锁。

因此C++11中引入了原子操作。所谓原子操作:即不可被中断的一个或一系列操作,C++11引入 的原子操作类型,使得线程间数据的同步变得非常高效。

原子类模板完全专门用于所有基本整数类型(bool 除外),以及 <cstdint> 中的 typedef 所需的任何扩展整数类型。 这些特化具有以下附加成员函数:

 在C++11中,程序员不需要对原子类型变量进行加锁解锁操作,线程能够对原子类型变量互斥的 访问。 更为普遍的,程序员可以使用atomic类模板,定义出需要的任意原子类型。

同时atomic_int与aotmic<int>完全一样

int main()
{
	atomic_int val = 0;
	vector<thread> threads(2);
	threads[0] = thread([&](int n) {
		for (int i = 0; i < n; ++i)
		{
			++val;
		}}, 100000);
	threads[1] = thread([&](int n) {
		for (int i = 0; i < n; ++i)
		{
			++val;
		}}, 200000);
	for (auto& e : threads)
	{
		e.join();
	}
	cout << val << endl;
	return 0;
}

这个程序就完全保证了++的原子性。

在C++11 中,原子类型只能从其模板参数中进行构造,不允许原子类型进行拷贝构造、移动构造以及 operator=等,为了防止意外,标准库已经将atmoic模板类中的拷贝构造、移动构造、赋值运算 符重载默认删除掉了。

原子操作的本质是CAS(compare and  swap): 寄存器中的值写回内存时,将当初提取的旧值与现在内存中的值比较,如果一样就写回去,如果不一样再次从内存中提取,重复操作。

mutex的种类

在C++11中,Mutex总共包了四个互斥量的种类:

std::mutex

C++11提供的最基本的互斥量,该类的对象之间不能拷贝,也不能进行移动。

函数名函数功能
lock()上锁:锁住互斥量 
unlock()解锁:释放对互斥量的所有权
try_lock()尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻 塞

std::recursive_mutex

递归互斥锁:其允许同一个线程对互斥量多次上锁(即递归上锁),来获得对互斥量对象的多层所有权, 释放互斥量时需要调用与该锁层次深度相同次数的 unlock(),除此之外, std::recursive_mutex 的特性和 std::mutex 大致相同。

判断获取锁的线程与当前要加锁的线程是不是同一个,如果是就不阻塞

std::timed_mutex

比 std::mutex 多了两个成员函数,try_lock_for(),try_lock_until() 。

try_lock_for()

接受一个时间范围,表示在这一段时间范围之内线程如果没有获得锁则被阻塞住(与 std::mutex 的 try_lock() 不同,try_lock 如果被调用时没有获得锁则直接返回 false),如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超 时(即在指定时间内还是没有获得锁),则返回 false。

try_lock_until()

接受一个时间点作为参数,在指定时间点未到来之前线程如果没有获得锁则被阻塞住, 如果在此期间其他线程释放了锁,则该线程可以获得对互斥量的锁,如果超时(即在指 定时间内还是没有获得锁),则返回 false。

std::recursive_timed_mutex不作讲解

guard_lock的改进版本unique_lock

与lock_gard类似,unique_lock类模板也是采用RAII的方式对锁进行了封装,并且也是以独占所 有权的方式管理mutex对象的上锁和解锁操作,即其对象之间不能发生拷贝。在构造(或移动 (move)赋值)时,unique_lock 对象需要传递一个 Mutex 对象作为它的参数,新创建的 unique_lock 对象负责传入的 Mutex 对象的上锁和解锁操作。使用以上类型互斥量实例化 unique_lock的对象时,自动调用构造函数上锁,unique_lock对象销毁时自动调用析构函数解 锁,可以很方便的防止死锁问题。

条件变量condition_variable

条件变量本身不是线程安全的,需要和锁(只能是unique_lock,可以在条件等待时解锁)配合

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

反复询问,消耗CPU资源

int main()
{
	int val = 0;
	int n = 100;
	vector<thread> threads(2);
	threads[0] = thread([&]() {
		while (val <= 100)
		{
			if (0 == val % 2)
			{
				cout << this_thread::get_id() << "->" << val << endl;
				++val;
			}
		}
		});
	threads[1] = thread([&]() {
		while (val < 100)
		{
			if (val % 2)
			{
				cout << this_thread::get_id() << "->" << val << endl;
				++val;
			}
		}});
	for (auto& e : threads)
	{
		e.join();
	}
	//cout << val << endl;
	return 0;
}

条件变量等待唤醒

int main()
{
	int val = 0;
	int n = 10000;
	condition_variable cond;
	mutex mt;
	vector<thread> threads(2);
	threads[0] = thread([&]() {
		while (val <= n)
		{
			{
				unique_lock<mutex> ulk(mt);
				cond.wait(ulk, [&]() {return 0 == val % 2;});

				cout << this_thread::get_id() << "->" << val << endl;
				++val;
				cond.notify_one();
			}
		}
		});
	threads[1] = thread([&]() {
		while (val < n)
		{
			{
				unique_lock<mutex> ulk(mt);
				cond.wait(ulk, [&]() {return val % 2;});

				cout << this_thread::get_id() << "->" << val << endl;
				++val;
				cond.notify_one();
			}
		}});
	for (auto& e : threads)
	{
		e.join();
	}
	//cout << val << endl;
	return 0;
}

注意,下面两种使用完全一样:

while (i % 2) 
     cv.wait(lock); 


cv.wait(lock, [&i] {return i % 2 == 0; });

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

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

相关文章

Baumer工业相机中偏振相机如何使用Baumer堡盟GAPI SDK来进行偏振数据的计算转换输出(C#)

项目场景 Baumer工业相机堡盟相机是一种高性能、高质量的工业相机&#xff0c;可用于各种应用场景&#xff0c;如物体检测、计数和识别、运动分析和图像处理。 Baumer的万兆网相机拥有出色的图像处理性能&#xff0c;可以实时传输高分辨率图像。此外&#xff0c;该相机还具…

ansible自动运维——ansible使用临时命令通过模块来执行任务

大家好&#xff0c;这里是天亮之前ict&#xff0c;本人网络工程大三在读小学生&#xff0c;拥有锐捷的ie和红帽的ce认证。每天更新一个linux进阶的小知识&#xff0c;希望能提高自己的技术的同时&#xff0c;也可以帮助到大家 另外其它专栏请关注&#xff1a; 锐捷数通实验&…

【机器学习实战】Python基于SVD奇异值分解进行矩阵分解(八)

文章目录 1 前言1.1 奇异值分解1.2 奇异值分解的应用 2 简单计算SVD2.1 NumPy 计算 SVD2.2 scikit-learn 计算截断 SVD2.3 scikit-learn 计算随机 SVD 3 demo数据演示3.1 导入函数3.2 导入数据3.3 计算SVD 4 讨论 1 前言 1.1 奇异值分解 奇异值分解&#xff08;Singular Valu…

信息安全复习四:置换密码乘积密码隐写术

一、章节梗概 置换密码、Rail Fence密码、行置换密码、乘积密码、转子机、隐写术 二、置换技术 2.1 定义 重新排列明文字母&#xff0c;达到信息加密的目的。 与替代密码不同的是&#xff0c;原来明文中的字母同样出现在密文中&#xff0c;只是顺序被打断。 古典的置换密码…

.net6 core Worker Service项目发布部署到Linux,以守护进程服务的形式部署启动

一、发布项目 1、以文件夹形式 2、目标运行时选对应的平台&#xff08;Linux-x64&#xff09; 3、文件夹选项&#xff1a;在发布前删除所有现有文件 二、部署项目&#xff08;安装.net6环境&#xff1a;参考Linux安装 dotnet sdk 6.0&#xff09; &#xff08;1&#xff09;…

《Spring MVC》 第二章 让程序run起来

前言 Spring MVC 是 Spring 框架提供的一款基于 MVC 模式的轻量级 Web 开发框架。 Spring MVC 本质是对 Servlet 的进一步封装&#xff0c;其最核心的组件是DispatcherServlet&#xff0c;它是 Spring MVC 的前端控制器&#xff0c;主要负责对请求和响应的统一地处理和分发。C…

用好Python自然语言工具包-- 实例“基于本地知识库的自动问答”

首先鸣谢thomas-yanxin 本问中示例来自他在GitHub上的开源项目“基于本地知识库的自动问答”&#xff0c;链接如下&#xff1a; thomas-yanxin/LangChain-ChatGLM-Webui: 基于LangChain和ChatGLM-6B的针对本地知识库的自动问答 (github.com) 目录 1. 基础知识&#xff1a; …

JVM调优最佳参数

项目背景 C端的项目&#xff0c;用户量比较多&#xff0c;请求比较多。 启动参数表 Xmx指定应用程序可用的最大堆大小。 Xms指定应用程序可用的最小堆大小。 &#xff08;一般情况下&#xff0c;需要设置Xmx和Xms为相等的值&#xff0c;且为一个固定的值&#xff09; 如果该值…

HCIP之链路聚合、VRRP

链路聚合 链路聚合 --- 可以将多个物理接口绑定成一个逻辑接口&#xff0c;即将N条物理链路聚合为一条逻辑链路。可以在不升级硬件的条件下&#xff0c;达到增加带宽的效果 我们将逻辑链路&#xff0c;称为聚合链路&#xff0c;在华为设备中称为ETH-TRUNK链路&#xff08;这个技…

Vue表单进阶操作

多选框另类使用场景 这个复选框和上面爱好那个复选框是不一样的&#xff0c;它不需要收集value值&#xff0c;只需要知道是否被选择&#xff0c;也就是ture或false&#xff0c;这时候就可以安装输入框的方式去写&#xff0c;直接去定义字符串&#xff0c;而不是数组 然后把全部…

“esp8266mod模块连接机智云Arduino实现pwm调节led的亮度“+_+

经过几天的漫长的探索和调试&#xff0c;终于连上机智云了。 历经的困难&#xff1a;esp8266总是连接机智云app超时&#xff0c;连接无反应&#xff0c;无数据。 1、机智云开发者中心&#xff0c;新建数据点&#xff0c;生成muc代码包&#xff0c;具体配置可以参考其他文章。…

go破冰之旅·5·常量、变量、数据类型

成体系的、快速学通Go&#xff0c;就在此时&#xff0c;持续连载&#xff01; 上一篇&#xff1a; https://lan6193.blog.csdn.net/article/details/123454411https://lan6193.blog.csdn.net/article/details/123454411上文熟悉了Go的基础符号、基础规则&#xff0c;本文我们…

前端项目代码规范

一、变量与函数的命名&#xff08;变量名和函数名是最好的注释&#xff09; 通常情况下函数小陀峰、类名大陀峰、变量短横线/小陀峰、const全大写单词要表达出正确的语义&#xff0c;如&#xff1a;array类型或其它集合类型用英语复数格式、其它类型不要用复数格式区分函数为功…

async/await 在 C# 语言中是如何工作的?(下)

接《async/await 在 C# 语言中是如何工作的&#xff1f;&#xff08;上&#xff09;》、《async/await 在 C# 语言中是如何工作的&#xff1f;&#xff08;中&#xff09;》&#xff0c;今天我们继续介绍 SynchronizationContext 和 ConfigureAwait。 ▌SynchronizationContext…

【SVN已解决】修改svn服务端地址为ip或者域名地址的方法

介绍 这里是小编成长之路的历程&#xff0c;也是小编的学习之路。希望和各位大佬们一起成长&#xff01; 以下为小编最喜欢的两句话&#xff1a; 要有最朴素的生活和最遥远的梦想&#xff0c;即使明天天寒地冻&#xff0c;山高水远&#xff0c;路远马亡。 一个人为什么要努力&a…

Vue之指令详解与自定义指令

指令 想要了解自定义指令&#xff0c;那肯定得先明白什么是指令。 指令的本质&#xff1a;语法糖&#xff0c;标志位。在编译阶段 render 函数里&#xff0c;会把指令编译成 JavaScript 代码。 常见的Vue内置指令有&#xff1a; v-on 即 。v-on:click”function“&#xff…

Node【Express框架【二】】

文章目录 &#x1f31f;前言&#x1f31f;中间件&#x1f31f;中间件函数&#x1f31f;什么是中间件函数&#x1f31f;中间件函数可以做什么 &#x1f31f;Express中间件的类型&#x1f31f;应用级中间件&#x1f31f;路由器级中间件&#x1f31f;错误处理中间件&#x1f31f;内…

人为惨案之kube-controller-manager 不断重启根因溯源

文章目录 背景问题发现排查CSI provision排查kube-controller-manager查看controller log紧急恢复求助chatgpt 背景 2023年4月21日10:38:07&#xff0c;在集群中测试RBAC的时候&#xff0c;在kuboard的界面神出鬼没的删除了几个clusterRole。练习一个CKA的练习题目. Create a…

如何实现计算机上的文件共享

文件共享 第一步&#xff1a;设置无线热点第二步&#xff1a;设置本地用户权限第三步&#xff1a;设置共享文件夹第四步&#xff1a;打开自己的移动热点&#xff0c;并且让对方连接自己的热点第五步&#xff1a;让对方的电脑进行连接自己共享的文件 第一步&#xff1a;设置无线…

React-Redux详解

React-Redux详解 前言 React-Redux是一个用于在React应用中管理状态的第三方库。它是基于Redux架构的&#xff0c;提供了一种在React应用中高效管理状态的方式。React-Redux通过将Redux的核心概念和React组件相结合&#xff0c;使得在React应用中使用Redux变得更加简单和方便。…