| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> 280-C++互斥锁 条件变量 -> 正文阅读 |
|
[C++知识库]280-C++互斥锁 条件变量 |
1.如果g_num是原子的,就是说线程a++g_num的时候线程b不能++,线程b++g_num的时候,线程a不能++,所以最后的结果总是为11,而如果g_num不是原子的,那最后的结果有可能是11也有可能不是11 在定义g_num的时候就算加上volatile易变关键字也依然是不正确的 3.互斥量主要解决的是异步中对同一资源的竞争,互斥量的特点是我访问的时候你不能访问,你访问的时候我不能访问 线程a执行到mt.lock()的时候进行加锁,如果线程b此时也执行到mt.lock()了,发现已经加锁了,就阻塞住了,等待线程a执行完++和打印操作并解锁后,就会把线程b从阻塞唤醒到就绪,然后线程b加锁进行一系列操作等等,也有可能线程a循环回来以后发现还没有加锁,可能再一次加锁,所以解锁后线程a和线程b都有可能获得锁 宏观上线程a和线程b一起执行,微观上是交替执行 因为try_lock()并不会将线程阻塞,他会不断的尝试加锁,一直进行while循环 5.互斥量中的拷贝构造函数、赋值函数、移动构造函数、移动赋值函数被删掉了,只有构造函数和析构函数了 6.recursive_mutex递归锁的意思是说,在线程a中获得锁,rmtx.lock()后,调用另一个函数,该函数内也有rmtx.lock(),由于我们已经获得锁这个资源了,就可以继续执行,继续调用该函数,形成递归,当然,回退的时候一个rmtx.lock()应该对应着一个rmtx.unlock() 而普通锁是不能连续锁两次的,会导致程序崩溃 7.lock_guard也是只有构造函数和析构函数 lock_guard是互斥体包装器,为在作用域块期间占用互斥提供便利RALL风格机制,就是对lock()和unlock()做了一个包装,类似于智能指针,是智能指针的风格 std::lock_guardstd::mutex lock(mtx);实际上调用的就是mtx.lock(),当块作用域结束时,会将该对象析构掉,达到了在块作用域lock()和unlock()的功能,就是对lock()和unlock()进行了一个包装,类似于智能指针 9.条件变量是允许多个线程相互交流的同步原语,可以实现线程同步,它允许一定量的线程等待另一线程的提醒,然后再继续,条件变量始终关联到一个互斥 同步就是若干个线程可以有次序的执行 10.wait导致当前线程阻塞直至条件变量被通知,或虚假唤醒发生,可选的循环直至满足某谓词,这个谓词指的就是bool值,真和假 11.假如有三个线程,三个线程分别打印A、B、C,想要三个线程循环打印ABCABC… 必须有互斥量,条件变量,全局变量才能达到线程同步的目的 条件变量wait函数的特点:①阻塞当前线程,由就绪状态转为阻塞状态②把拥有锁的资源释放掉③获得互斥锁 假如先执行的是print_B()函数,先获得互斥锁,然后进入while循环,isReady!=1的值为真,执行wait函数,阻塞当前线程并将锁资源释放,将线程B放入阻塞队列中,假如然后执行的是print_C()函数,也是先获得锁(因为线程B在wait时将锁资源释放了,所以print_C()函数可以正常获得锁),进入while循环,isReady!=1的值为真,执行wait函数,阻塞当前线程并将锁资源释放,将线程C放入阻塞队列中,假如然后执行print_A()函数,获得锁,进入while循环,isReady!=0为假,不进入循环,打印出A,并将条件变量isReady的值改为1,并唤醒阻塞队列中所有等待的线程,然后再次进入while循环,此时isReady!=0为真,阻塞当前线程并将锁资源释放,将线程A放入阻塞队列中,以此类推可以循环打印ABCABC… 实际上线程之间是抢夺互斥锁的,谁抢上了就执行哪个线程 解决惊群现象可以使用notify_one唤醒一个线程,但是并不确定唤醒的是哪一个线程,如果唤醒的是不想唤醒的线程,就会导致白白被唤醒,所以如何精准唤醒是很重要的,就是A去精准唤醒B,B去精准唤醒C,C再精准唤醒A 12.条件变量的底层有一个等待队列 13.唤醒并不意味着一定会从等待队列中取出,必须要获得锁资源后才能从等待队列中取出 14.如果将里面的notify_all都改为notify_one会怎么样? 有可能会正常打印,比如说先运行a,然后运行b,然后运行c 也有可能就死掉了,比如先运行c,c不满足,将c放入等待队列中,然后运行b,b也不满足,将b放入等待队列中,然后运行a,a满足,唤醒bc其中的一个线程,并将a放入等待队列中,假如唤醒的是c,c并不满足条件,将c放入等待队列中,此时abc都在等待队列中,没有线程可以去执行notify_one 16.锁的粒度 假如有两个线程,对于Mysql数据库的表来说,如果它有一个表锁,那么线程1获得表锁的以后,线程2就不能获得表锁,必须等待线程1释放表锁后才能获得,而如果每一条记录都有一个锁,就是行锁,只有当线程1和线程2都访问同一条记录时,才能阻塞,否则就可以同时对表进行操作 锁的粒度越小,并发性就越高,但是耗损的资源就越多,锁的粒度越大,并发性就越低,但是耗损的资源就越少 所以要在粒度和并发性上面有一个平衡 17.条件变量头文件#include <condition_variable> 18.死锁,就是出现一个我等你你等我的状态 线程1获得资源1,然后睡眠一会,线程2获得资源2,然后睡眠一会,这时线程1希望获得资源2,但是此时资源2被线程2占用,就会等待线程2释放资源,同样线程1希望获得资源1,但是此时资源1被线程1占用,就会等待线程1释放资源,这就是死锁,出现我等你你等我的情况 程序中睡眠的意思是说,在其中进行了一些操作,拿睡眠来代替这些操作 产生死锁的原因:互斥、占有等待、不可抢占、循环等待 这个程序就是因为占有等待导致死锁 |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 3:04:01- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |