个人主页:平凡的小苏
学习格言:命运给你一个低的起点,是想看你精彩的翻盘,而不是让你自甘堕落,脚下的路虽然难走,但我还能走,比起向阳而生,我更想尝试逆风翻盘。
C++专栏:C++内功修炼基地
> 家人们更新不易,你们的点赞和⭐关注⭐真的对我真重要,各位路 过的友友麻烦多多点赞关注。 欢迎你们的私信提问,感谢你们的转发! 关注我,关注我,关注我,你们将会看到更多的优质内容!!
对于C++线程库,必须分配了线程关联函数,线程才被创建启动。
两个线程都可以调用Func1函数,在调用函数时,两个线程会各自创建自己的栈空间,所以回调函数的栈区变量从属于各个线程,线程间互不影响。
由图可知,Func2的效率更高,为什么呢?
因为我们只进行了++操作,操作系统是非常快速的,所以++操作所耗费的时间是没有加锁和解锁所耗费的时间多的,我们要根据实际情况来放置加锁与解锁的逻辑,使它能够更高效的运行。
这里是因为加锁后还没有解锁就去递归,造成了死锁问题。所以我们需要使用递归互斥锁
还有其他锁,比如定时锁和递归定时锁
这里借助了类的构造函数和析构函数来解决问题。这样就不怕抛异常后没有进行解锁的问题
CAS(Compare and Swap)操作是一种常见的并发编程技术,用于保证多个线程访问同一共享资源时的数据一致性。它可以在不使用锁的情况下实现对共享变量的原子更新操作。
CAS操作通常由三个参数组成:内存地址V、预期值A和新值B。当多个线程同时尝试更新V时,只有其中一个线程能够成功执行CAS操作,即当且仅当V的当前值等于A时,才会将其更新为B。如果V的当前值不等于A,则说明其他线程已经修改了V,那么当前线程会放弃更新操作,并重新尝试。
CAS操作通常用于实现无锁算法,在高并发场景中可以提高程序的并发性能。但是,CAS操作也存在一些问题,例如ABA问题和自旋次数过多等,需要开发者在实际应用中注意避免和解决。
atomic可以使线程并行。底层的本质就是CAS操作,写入时会去比对之前保存的值,如果不一样,说明已经有线程进行了修改,那么该线程将舍弃本次计算结果,重新计算、比对。
条件变量本身并不是线程安全的。
一个线程在调用wait函数后,会被阻塞挂起,同时释放自己手上的锁。当另一个线程调用notify_one函数后,将重新唤醒该线程,该线程自动获得当初释放的那把锁。所以,这也是wait函数传入的形参必须是unique_lock的原因。使用条件变量控制偶数先打印的两种代码:
问题二:如何防止一个线程不断运行
#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连续打印。这样会增加线程负担