【C++】多线程

🌇个人主页:平凡的小苏
📚学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风翻盘
🛸C++专栏C++内功修炼基地
> 家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真重要,各位路 过的友友麻烦多多点赞关注。 欢迎你们的私信提问,感谢你们的转发! 关注我,关注我,关注我,你们将会看到更多的优质内容!!

在这里插入图片描述

一、C++多线程库

在这里插入图片描述

对于C++线程库,必须分配了线程关联函数,线程才被创建启动。

1.线程都有独立的栈空间

在这里插入图片描述

两个线程都可以调用Func1函数,在调用函数时,两个线程会各自创建自己的栈空间,所以回调函数的栈区变量从属于各个线程,线程间互不影响。

2.加锁串行与并行的效率

在这里插入图片描述

由图可知,Func2的效率更高,为什么呢?

因为我们只进行了++操作,操作系统是非常快速的,所以++操作所耗费的时间是没有加锁和解锁所耗费的时间多的,我们要根据实际情况来放置加锁与解锁的逻辑,使它能够更高效的运行。

3.C++递归互斥锁

在这里插入图片描述

这里是因为加锁后还没有解锁就去递归,造成了死锁问题。所以我们需要使用递归互斥锁

在这里插入图片描述

还有其他锁,比如定时锁和递归定时锁

4.lock_guard(RAII风格的锁)/unique_lock(可随时释放锁)

在这里插入图片描述

这里借助了类的构造函数和析构函数来解决问题。这样就不怕抛异常后没有进行解锁的问题

5.CAS操作

CAS(Compare and Swap)操作是一种常见的并发编程技术,用于保证多个线程访问同一共享资源时的数据一致性。它可以在不使用锁的情况下实现对共享变量的原子更新操作。

CAS操作通常由三个参数组成:内存地址V、预期值A和新值B。当多个线程同时尝试更新V时,只有其中一个线程能够成功执行CAS操作,即当且仅当V的当前值等于A时,才会将其更新为B。如果V的当前值不等于A,则说明其他线程已经修改了V,那么当前线程会放弃更新操作,并重新尝试。

CAS操作通常用于实现无锁算法,在高并发场景中可以提高程序的并发性能。但是,CAS操作也存在一些问题,例如ABA问题和自旋次数过多等,需要开发者在实际应用中注意避免和解决。

6.atomic原子操作

在这里插入图片描述
在这里插入图片描述

atomic可以使线程并行。底层的本质就是CAS操作,写入时会去比对之前保存的值,如果不一样,说明已经有线程进行了修改,那么该线程将舍弃本次计算结果,重新计算、比对。

7.条件变量

在这里插入图片描述

条件变量本身并不是线程安全的

一个线程在调用wait函数后,会被阻塞挂起,同时释放自己手上的锁。当另一个线程调用notify_one函数后,将重新唤醒该线程,该线程自动获得当初释放的那把锁。所以,这也是wait函数传入的形参必须是unique_lock的原因。使用条件变量控制偶数先打印的两种代码:

问题一:如何保证t1先运行,t2阻塞
在这里插入图片描述

问题二:如何防止一个线程不断运行

#include <iostream>
#include <algorithm>
#include <thread>
#include <mutex>
using namespace std;
int x = 0;
mutex mtx;
condition_variable cv;

int main()
{
	int n;
	cin >> n;
	thread t1([&, n]() {
		while (1)
		{
			unique_lock<mutex>lock(mtx);
			if (x >= 100) break;
			if (x % 2 == 0)//x等于偶数阻塞
			{
				cv.wait(lock);
			}
			cout << this_thread::get_id() << ":" << x << endl;
			++x;
			cv.notify_one();
		}
		});
	thread t2([&, n]() {
		while (1)
		{
			unique_lock<mutex>lock(mtx);
			if (x > 100) break;
			if (x % 2 != 0)//x 等于奇数就阻塞
			{
				cv.wait(lock);
			}
			cout << this_thread::get_id() << ":" << x << endl;
			++x;
			cv.notify_one();
		}
		});
	t1.join();
	t2.join();

	return 0;
}

为什么要反之一个线程连续打印?

  • 假设t1先获取到锁,t2后获取到锁,t阻塞在锁上面
  • t1打印奇数,++x,x变成偶哦书
  • t1 nodify,但是没有线程wait
  • t1出了作用域解锁,t1时间片到了,切出去了
  • t2获取到锁,打印,notify,但是没有线程等待,lock出作用域,解锁。
  • 假设t2 的时间片充足,再次获取到锁,如果没有条件控制,就会导致t2连续打印。这样会增加线程负担
  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平凡的小苏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值