操作系统——信号量(L16,L17,L18,L19)

进程同步与信号量:

在这里插入图片描述如生活中的司机和售票员的合作,就体现了两个进程之间的合作
在这里插入图片描述这里的代码就体现了两个进程之间的合作,他们使用共享数据来操作自身的停止和运行,当生产者判断counter为10,则进行停止,直到消费者进行了一次操作;当消费者判断counter为0,则进行停止,直到生产者中进行了一次操作,这样便实现了信号控制,但是这里的counter显然是需要互斥控制的。
在这里插入图片描述在这里插入图片描述使用上述代码,当生产者为多个的时候就出现问题了,当缓冲区满p1进行生产首先会阻塞,然后生产者p2进行生产也会阻塞,这时候counter的为5,且不会变换,消费者也只会进行一次counter-1的操作且释放一个生产者p1,这时候的counter为4了,这时候生产者p2就永远不会被释放了因为counter的值已经变为4了。主要就是用counter表示的二元关系已经不能实现多个生产者或多个消费者出现的情况。这时候我们就需要使用信号量的概念了

在这里插入图片描述
信号量需要在信号的基础上记录下一共阻塞了多少个进程,用于进行相应次数的唤醒操作

在这里插入图片描述生产者生产一个进行-1,消费者消费一个进行+1
可以将sem看成一个空闲缓冲区数量,当c执行一次就+1,当p执行一次就-1,当sem为0表示缓冲区满了,当sem为负数表示有p在等待(也就是欠几个空闲缓存区)

在这里插入图片描述生产者开始需要P(sem),当value执行了 – 操作,得到的数值小于0,表示仓库中有资源满了,自己就可以睡眠了,可以将CPU给其他进程使用,当大于0,表示仓库中还有消费者在等资源,这是否就应该继续生产

V(semaphore s){
	s.value++;
	if(s.value<=0){
		wakeup(s.queue);
	}
}

消费者当发现value++后得到的value的值小于等于0,这就表示value的值在没有++之前小于0,也就是有生产者在等待,这时候就使用wakeup来唤醒一个队列中的生产者

在这里插入图片描述

信号量的保护:

完整的信号量包括对于临界区的保护,也就是对于sem变量的修改同一时间只能有一个操作
在这里插入图片描述在这里插入图片描述在这里插入图片描述通过加锁的方式,使得在加锁期间的时钟停止
在这里插入图片描述在这里插入图片描述需要保证每次只能有一个进程进入到临界区中,且每个需要进入临界区的进程都能得到进入
在这里插入图片描述通过一个turn变量,当turn等于0进程0执行,当turn等于1进程1执行,且二者执行完都将turn翻转,这样我们可以推出当p0的临界区和p1的临界区同时执行的时候turn等于0且1,由此可以推出这个方法是正确的,这种方式就是值日的方式
在这里插入图片描述除了值日的方式,我们还可以进行留便条的方式
在这里插入图片描述
我们使用留便条的方式可以得到上述代码,当对应的进程需要进行留便条就将自己的flag对应的值置为true,然后判断其他人的flag值,如果为true表示对方进入了临界区,但是这样的方式存在死锁问题

在这里插入图片描述
考虑上述执行序列存在死锁问题
在这里插入图片描述这里主要是妻子发现丈夫没有留条且没有牛奶就去买,丈夫则是当发现妻子没有留条后进行等待,当等待完了发现还是没有牛奶就再去买,这样妻子就可以完整的运行不需要进行等待操作,可以随时remove自己的便条,这样丈夫就可以不需要已知等待

在这里插入图片描述值日和标记的方法,flag表示自己的意愿,turn==0表示P0值日,turn ==1表示P1值日
当turn条件成立,则让指定进程执行,当turn不成立,但是对方去执行了空转;当自己执行完,flag置为false保证对方可以执行

在这里插入图片描述在这里插入图片描述
这里的i指的就是一个进程的就绪队列号,第一个wiile循环主要是等待选号完成
在这里插入图片描述这种算法易发生发生溢出且算法麻烦
在这里插入图片描述
多cpu不同的cpu的寄存器不同,这就不能保证临界区的保护,每条指令执行完,就进行一个是否需要中断的判断,cli指令就是将这个中断关掉,这是所有的中断都不发生,sti指令是将这个中断打开
在这里插入图片描述
使用一条指令来覆盖testandset中的代码

信号量的代码实现:

在这里插入图片描述
信号量是内核对象,通过对比名字是否相同,通过open打开信号量,再通过信号量的value值的大小,确定下一步动作

在这里插入图片描述
这里的ll_rw_block函数主要做的就是启动读磁盘功能,wait_on_buffer函数就是将自己阻塞也就是下面的lock_buffer的代码,去掉bh->b_lock=1这一行(不知道为啥要贴lock_buffer的代码在这里……),也就是bh如果有人访问就将自身阻塞(这个主要是sleep_on函数中做的),否则就继续执行

在这里插入图片描述
对sleep_on函数的分析:sleep_on函数创建了一个tmp变量,这个操作是在内核中完成的,所以tmp变量也是在内核栈中的变量(关于内核栈的内容可以看之前的关于进程切换的内容),p为一个二级指针,将p指向的地址写入到tmp中,然后将p的内容指向当前的pcb,也就是将自己放入到p的第一个,将之前的p的第一个放入到tmp中

在这里插入图片描述

当下一次进行读磁盘中断,将b_lock值变为0表示可以抢占bh了,然后wake_up中将队首pcb的状态变为0,表示进程位于等待状态(当下一次有调度到来,变量队列中的pcb就会发现这个进程为等待,就可能会调用它),当这个进程得到了cpu时间,那么程序就运行到了if(tmp)这一句了,也就是上一次切换后的下一句,也就是sleep_on的最后几句。最后将tmp指向的pcb的状态置为0,这样就导致了所有等待bh的进程都被唤醒了。
但是这里有些问题,因为调度的时间不是确定的,所以不能百分之百保证的当上一个进程被唤醒,这个进程不会立刻切换到下一个进程去唤醒下下个进程。

死锁:

在这里插入图片描述
二者相互等待对方放弃资源,所以造成了死锁
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述
银行家算法的代码:https://blog.csdn.net/ychychych1/article/details/116456655
在这里插入图片描述通用pc上都是通过忽略的方式,因为重启的代价小

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值