【C++】多线程

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

在这里插入图片描述

一、C++多线程库

【C++】多线程_第1张图片

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

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

【C++】多线程_第2张图片

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

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

【C++】多线程_第3张图片

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

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

3.C++递归互斥锁

【C++】多线程_第4张图片

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

【C++】多线程_第5张图片

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

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

【C++】多线程_第6张图片

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

5.CAS操作

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

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

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

6.atomic原子操作

【C++】多线程_第7张图片
【C++】多线程_第8张图片

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

7.条件变量

【C++】多线程_第9张图片

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

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

问题一:如何保证t1先运行,t2阻塞
【C++】多线程_第10张图片

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

#include 
#include 
#include 
#include 
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连续打印。这样会增加线程负担

你可能感兴趣的:(C++修炼内功,c++,java,开发语言)