![1b16f180a84eaad72c1a439b8c53a612.png](https://i-blog.csdnimg.cn/blog_migrate/d56a267cc45a1b11a864b159f4356c2d.jpeg)
论处于考试周的学生现状:论文肝到底,天天push,坐在电脑前就是一整天,只要还有一个根头发,都不能阻挡我肝的步伐。终于,等到最后一门结束时,我发出了脱缰野马般的咆哮~~~
哈喽,各位老铁,我又带着干货来啦。
操作系统中的线程、锁机制和PV操作
01
线程
线程是可由CPU直接运行的实体,是程序中的执行路径,一个进程可以创建多个线程,多个线程共享CPU可以实现并发运行。同时线程的并发粒度比进程的并发粒度更细。
单线程程序
整个进程中只有一个线程。Window程序缺省只有一个线程(主线程,main线程)
多线程程序
整个进程中至少有两个线程。主线程和至少一个用户线程。
线程技术的典型应用场景
程序的多个功能需要并发运行
在线视频:
![04dc5dfdb6616bf9206ed11fa15e5380.png](https://i-blog.csdnimg.cn/blog_migrate/b222121c2fadd00eba6d2ff00eb7e29c.png)
并发的功能:视频的解码、音频的解码,网络接受,显示和播放音视频等等,这些都需要并发运行,才能给我们良好的体验感和沉浸感。
Microsoft Windows的文件拷贝程序是个多线程程序
![51e54eed1c74f8d420aeac105052cc5f.png](https://i-blog.csdnimg.cn/blog_migrate/ae664cf01f0c1fc462eb9f9aa4bdf6d0.png)
多核心CPU上的应用,利用多线程可以更好的发挥多核性能
使用多线程的麻烦事儿
![44e56baf06ae9c2448f179f37207e415.png](https://i-blog.csdnimg.cn/blog_migrate/ed852f19a36a77d40d23b69de02e4138.png)
虽然使用线程可以帮我们解决很多问题,线程也存在着一些问题,需要克服,第1个就是一个程序来说,如果单线程程序来说程序是依次往下运行的,逐行逐行的,往下运行的,如果是多线程程序,那么程序的运行是并发的,所以这个程序在调试的时候,它就不一定是按照这个我们预想的一行一行的运行,过程难以控制,同时存在那么多个并发运行的线程,多线程可能会同时对这个共享变量进行一个程序操作,会不会多个线程的同时来访问?这就回带来很多的麻烦事儿;另外就是线程的安全问题。
02
临界区
临界区和临界资源
并发错误:对于一个内存全局变量k,有程序a和程序b如下:
程序A:...k = 100;...printf("A : k = %d",k);......
程序B:...k = 200;...printf("B : k = %d",k);......
如果两个程序并发运行,两个程序的打印结果是不确定的,既可以是100也可以是200。
假设程序A在执行 ``printf()`` 语句之前由于需要其他操作,暂时停止运行,而程序B无阻碍的运行,就会在程序A打印变量 ``k``之前将其值修改为200,进而使得程序A的打印结果不再是理论上的100.这就会出现程序的并发错误。
![e3b6f6c3104398b96374c330dd345f55.png](https://i-blog.csdnimg.cn/blog_migrate/6c247ce4059f31b845f46e268db6336e.png)
那有什么好的解决方案吗?
![97d77a9443466f7f114f68662a489490.png](https://i-blog.csdnimg.cn/blog_migrate/fa2aacf1311aadcbc25db46b5932a4be.png)
答案:程序设定一个特定的区域不让两个程序同时进入运行,只能先后进入。
![13a969ec91402e590820274640458129.png](https://i-blog.csdnimg.cn/blog_migrate/19ccda94bf53921ad2a25e6b118a68c7.png)
临界资源
一次只允许一个进程独占访问和使用的资源(如内存中的共享变量)
临界区
进程中访问临界资源的程序段。
临界区和临界资源的访问特点
1.具有排他性
2.并发进程不能进入到临界区
设计临界区访问机制的原则
既然临界区对程序能够正确地并发运行很重要,那么在操作系统中,就需要设计出合理而高效的临界区访问机制,来达到这一目的,而在设计访问机制时需要有一定原则。
忙则等待
当临界区忙时,即是已经有进程进入到了临界区,其他进程必须在临界区外等待当前进程在临界区中完成运行。
空闲让进
当无进程处于临界区时,任何有权进程都可以进入临界区。
有限等待
进程进入临界区的请求应在有限时间内得到满足。简单来说就是假设一个进程A进入了临界区执行,此时进程B在临界区外等待,但是操作系统不能让进程B 长时间的等待,使其处于资源缺乏的饥饿状态。思考: 临界区的设置大些还小些好?答案:临界区的设置不能无根据的扩大,这样会使得其他需要进入该临界区的进程的等待时间变长,临界区的大小设置是根据不同进程的实际情况而定,总之在不影响进程执行得到正确结果的情况下,越小越好。
让权等待
![e16972535fdd1f85692667be567feb96.png](https://i-blog.csdnimg.cn/blog_migrate/06f0d08223bdacdb0508c79ceac1124d.png)
等待进程放弃CPU(让其他的进程有机会得到CPU)
当一个进程到达临界区时,CPU会询问其是否可以进入临界区,当不能进入时,此时该进程进入等待状态,此时它应该放弃CPU,将控制权交还给操作系统,调度程序调度其他进程进行运行,而不是让CPU一直询问是否能够进入临界区。
03
锁机制
基本原理
设置一个标志,来判断当前临界区是否可以进入
![f43702e5ad1475cfa08f5570644891fb.png](https://i-blog.csdnimg.cn/blog_migrate/c05535140d4e0971dd420a2a2d54b2f8.png)
其实这可以通俗的理解为:
临界区-->卫生间、锁标志-->卫生间门(不恰当的比喻 ^ _ ^)
当一个进程需要进入某个临界区时,首先检查该临界区的标志(卫生间门是否是开着的)是否为可用,是则进入,反之等待。进程进入到临界区后,将标志更改为不可用(进入卫生间要关门),退出临界区时将标志修改为可用(出卫生间要开门)。
上锁操作
Lock(S) {//上锁原语 test:if (S == 0 ) { goto:test;//测试锁标志 } else { S = 0;//上锁 }}
开锁操作
Unlock(S) {//开锁原语 S = 1;}
04
PV操作解决进程同步问题
同步机制的实质
- 运行条件不满足时,能够让进程阻塞
- 运行条件满足时,能够让进程立即继续
P-V操作应用与进程同步的基本思路
- 暂停当前进程:在关键操作前执行P操作---->必要时可暂停
- 继续进程:在关键操作之后执行V操作------>必要时唤醒合作进程
- 定义合理并且有意义的信号量,设置合适的初值
实例:公交车司机和售票员
时间回到2010的那个年代,想必大家都做过有售票员的公交车或者客车,这里以这个场景为例,来展示如何利用P-V操作实现进程间的同步
司机:起步、驾驶、停车
售票员:开门、售票、关门
同步要求:
- 只有在售票员将车门关好之后,司机才能够起步
- 只有司机停好车之后,售票员才能够打开车门
很容易就可以分析出:司机的关键操作是起步和停车;而售票员的关键操作是开门和关门。
关键操作的判断条件
该操作的执行需要一定的条件(在该操作之前添加P操作)
该操作执行完成与否影响到合作进程的某个操作(在该操作之后添加V操作)
![ef1c223c3174b2faad1d178f27c6900e.png](https://i-blog.csdnimg.cn/blog_migrate/d2e1f3d2220c8d771bacaf96d7f74d04.png)
假设司机进程先运行,首先执行P操作,判断门是否关好,初值为0,未关好,则司机进程阻塞,售票员进程继续执行。
![9c8ddafdc2bae470fbf01758eb7096f4.png](https://i-blog.csdnimg.cn/blog_migrate/7469df98bdf1832be3ff2ae6024e8957.png)
售票员执行关门操作:然后执行V操作:s1= 0 并且唤醒司机进程
![90ff788aed4a8ee6cb6766c55c97de4c.png](https://i-blog.csdnimg.cn/blog_migrate/2e2db1623b939f940d757427ec746992.png)
司机和售票员并发执行驾驶和售票操作,互不影响:
![93e1fcc35a7a9d7574bf64c3293e600d.png](https://i-blog.csdnimg.cn/blog_migrate/4924b0047469f513ace04c2c41e6870d.png)
假设此时即将到站,售票员试图开门,会先执行P操作:判断车是否停好,此时S2 = 0,售票员进程会被阻塞,S2 -> -1;
![f588729f4a4c3a7cdea66c774c07d3ef.png](https://i-blog.csdnimg.cn/blog_migrate/ec9938f99ff44d494c384627fc12a078.png)
司机进程继续,然后执行停车操作,停好车之后,执行V操作,使得S2 = 0 ;并唤醒售票员进程:
![049a483c91f8d1cada830038bbf4f39b.png](https://i-blog.csdnimg.cn/blog_migrate/f0b3e3b8492a1f0fc16f74fdc7575f71.png)
至此,该司机和售票员的一个进程同步过程就顺利完成了。
![334fa95de52f56e688c81ee65ab410df.png](https://i-blog.csdnimg.cn/blog_migrate/016d5c3c91be1c0d19110ba34e80d6bc.jpeg)
然Coder
微信号 : huazai990728
CSDN:LengDanRan
![9bcd984bbffa25f04c67d2f8fba6a4ff.gif](https://i-blog.csdnimg.cn/blog_migrate/8dd3a5828d21703cbfccbbc0bc6e9be9.gif)
分享、在看与点赞
只要你点,我们就是胖友
![9bcd984bbffa25f04c67d2f8fba6a4ff.gif](https://i-blog.csdnimg.cn/blog_migrate/8dd3a5828d21703cbfccbbc0bc6e9be9.gif)