学习日期:2024.7.9
内容摘要:信号量机制,用信号量实现进程的同步与互斥
信号量机制
信号量的概念
在上节内容中,我们学习了进程互斥的软件和硬件解决方案,但这些方案都有各自的问题,双标志法都因为检查和上锁两个步骤不能一气呵成,会导致两个进程一起进入临界区,而Peterson算法和几个基于硬件实现方式的方法虽然解决了这些问题,但这些方法都会导致忙等。
1965年,荷兰科学家Dijkstra(就是《数据结构》图论那位)提出了一种实现进程同步、互斥的方法——信号量机制。
信号量其实就是一个变量(可以是一个整数,也可以是更复杂的数据结构的变量),可以用一个信号量来表示系统中某种资源的数量,比如系统只有一台打印机,就可以设置一个初始值为1的信号量。
用户进程可以通过操作系统提供的一对原语来对信号量进行操作,从而很方便的实现进程互斥和同步。
一对原语:wait(S)原语和signal(S)原语,信号量S是函数调用时传入的一个参数,而wait和signal两个原语常简称为P,V操作(来自荷兰语proberen和verhogen),简写为P(S)和V(S)
整型信号量
用一个整数型的变量作为信号量,用来表示系统中某种资源的变量。
例:假如某系统中有一台打印机,初始化整型信号量S,S=1。P操作是占用资源,S=S-1,V操作是释放资源,S=S+1,每次调用之前先判断S的值,如果S>=1,就P一次,否则等待。
逻辑很简单,就是用S来计数,因为用了原语实现检查和上锁一气呵成,避免了并发、异步导致的问题。
缺点:还是要利用while结果循环等待,不满足“让权等待”原则,没有解决忙等问题。
记录型信号量(重点)
整型信号量的缺陷是存在忙等问题,因此人们又提出了记录型信号量,即用一种记录型数据结构表示信号量
假如S=2,每次进行一次P操作,S.value--,每次执行一次V操作,S.value++,如果P操作后小于0,进程阻塞,且当S为负时,S.value的绝对值就是正在等待资源的进程的数目。
P操作中一定是先S.value--,之后如果S<0再block;V操作中一定是先S.value++,之后如果S.value<=0再wakeup。注意理解原因!
S.value的初始值表示系统中某种资源的数目,S.value++后<=0,说明有进程在等待资源,因此调用wakeup原语唤醒等待队列中的第一个进程(被唤醒进程从阻塞态转换为就绪态)。
S.value==0,资源恰好分配完,S.value==-x,有x个进程正在等待资源。
因为在资源不足时,进程会使用block原语自我阻塞,主动放弃处理机,所以遵循了让权等待原则,不会出现忙等。
用信号量机制实现进程的同步与互斥
一个信号量对应一种资源,信号量的值=这种资源的剩余数量(信号量的值如果小于0,说明有进程在等待这个资源,绝对值即为等待的进程数)
信号量机制实现进程互斥
1.分析并发进程的关键活动,划分临界区
2.设置互斥信号量mutex,初始值为1,对不同的临界资源要设置不同的互斥信号量
3.在进入区P(mutex),申请资源
4.在退出区V(mutex),释放资源
注意:P,V操作必须要成对出现,申请资源和释放资源一定会成对出现。
信号量机制实现进程同步
知识回顾:进程同步:让各并发的进程按照某种我们期望的顺序推进。
1.分析什么地方需要同步关系,即分析需要“一前一后”的两个(或更多)操作
2.设置同步信号量S,初始值为0
3.在“前操作”之后执行V(S)
4.在“后操作”之前执行P(S)
比如说两个进程A,B,我们希望A先执行,B后执行。此时S代表一个信号,即A已经完成的信号。在A执行完之后,释放信号,在B执行之前,检查信号。简记为“前V后P,前后后前”
如果先执行到B,因为会先进行P(S)操作,此时S--后S=-1,表示此时没有可用资源,因此P操作中会执行block原语,进程会进入阻塞队列。当执行完A之后,S++,此时S>=0,就会在V操作中执行wakeup原语,唤醒B进程,这样就实现了按我们期望的顺序推进进程。
感谢您看到这里,如果满意的话麻烦您点个赞支持一下,个人主页还有更多内容分享。
内容总结自王道计算机考研《操作系统》 和 人民邮电出版社《操作系统导论》