哈工大-操作系统L18

信号量的代码实现


除了用户态需要大量的信号量操作系统内部也需要大量的信号量

一.写操作

sd=sem_open("empty")( 打开一个empty的信号量)申请信号量,因为信量是在操作系统内部的,信号量包括一个值value还有PCB队列,多个进程都需看到value根据value来工作,多个进程都能看到的值应该放在内核里,PCB又是内核的数据结构,所以信号量这个数据结构应该在内核里,在内核里就需要系统调用来获取,大家来共享这个内核这个结果

typedef struct char name[20]信号量的名字,在semtable[20]中根据名字找到信号量,生产者使用了这个信号量比如说empty,消费者也需要使用empty,这样大家就可以共同看见这个值value,从而根据value进行休眠或者唤醒操作

sem_wait(sd)看是否有空闲缓冲区,由于本课程是根据单cpu,linux-0.11来学习的所以可以使用中断开关来保护信号量,cil()关中断,if(semtable[sd].value)判断value的值小于0将自己设置成阻塞,再将自己放到阻塞队列中,然后schedule()切换,sti()关中段,如果有资源就执,write(fd,&i,4)向fd文件中写入5个字每个字4个字节

二.读操作

bread(int dev,int block)读磁盘块,buffer_head*bh,申请一段空闲缓冲,ll_rw_block(READ,bh)启动读命令,wait_on_buffer(hb)睡眠,等待磁盘读完之后唤醒,lock_buffer()bh->b_lock=1进入休眠,可是这里是为什么要使用while()而不使用if()呢?先挖个坑一会再说。

temp=*p;*p=current,将自己放入阻塞队列,current->state=TASK_UNINTERRUPTIBLE将自己设置成阻塞状态。schedule()切换

p指针永远指向队首,tmep=*p,temp指向task_struct,*p=current,指向当前的TCB,新的阻塞队列的队首就是current,task_struct和tmp需要连接起来,这个连接非常的隐蔽,temp在当前进程的内核栈里,进程切换的时候,内核栈也跟着切换,所以task_struct就可以找到当前进程的TC找到当前进程的内核栈,在内核栈中找到temp,而temp指向下一个进程TCB,TCB指向下一个进程的内核,内核栈的tmp指向下一个进程的TCB.....

这个阻塞队列可以看成是一个头插入的链表

unlock_buffer()队列唤醒,bh->b_lock=0,解锁,wake_up根据队首指针p唤醒, 执行完后会跳转到

if(tep)判断是否有下一个进程,如果有就把下一个进程唤醒,依次这样执行将阻塞队列中的所有进程全部唤醒

将阻塞队列第一个唤醒的机制,是种正常机制,假设用第一个写操作队列,第2个进程永远排在第1个进程的后面,第1个经常总是先执行,但是后面的进程可能优先级更高,而当前这种唤醒全部进程的方法,就可以通过让schedule()来执行优先级更高的进程,由于只允许一个进程执行,当这个被选择的进程执行的时候,其它经常也会执行,因为其它进程也被唤醒了,这个就时候就需要用while()来重新判断,进程是否再次休眠,如果使用if()就会导致被唤醒的进程全部执行了。

这种方法不需要负数,不需要记录有多少个进程,由while来弥补负数缺少的功能
 

  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值