【进程间通信】信号量

这里的信号量是指内核中支持,在系统空间实现,只不过由用户进程直接使用;要与内核中信号量向区分;


(1)创建或寻找信号量在semget()完成的;sys_semget()与sys_msgget()几乎是一样的,只不过将newque换成了newary();在newary()中,此时entries指向同一个ipc_id数组,数组中p指向一个ipc_perm,此时它的数组变成了sem_array数据结构;在sem_array中有个sem_base指针,它是一个结构数组,每一个sem都是一个信号量,它的大小由nsems,与sem_array在一起分配的;sys_semget可以建立一组而不是一个信号,主要是为了防止死锁,在SEMOP操作中,要么取得所有的共享资源的使用权,或者是不占用任何共享资源地等待;

(2)信号量操作在semop()完成的;在sys_semop()中,tsops指向用户空间的一个sembuf结构数组,而nsops则是数组的大小 ;数组中每一项都规定了对一个信号的操作,而对数组中所有的规定的操作也都是原子的;在sembuf结构体中,sem_num为具体信号在通过SEMGET建立的一组信号量中的下标,sem_op则为一个小整数,可取-1,0,1,表示相应的资源操作,semflg是个标志位,若是IPC_NOWAIT,表示条件不能满足时就不要等待睡眠,立即返回,SEM_UNDO表示如果昂前进程exit()时未还申请的资源,就要由内核代为退还;先使用copy_from_user将sembuf数组拷贝过来;先使用sem_lock加锁和sem_checkid()检查一体化标号;然后是对所有的信号量操作进行一番统计;看看哪几项是要改变信号来那个的,哪几项是要SEM_UNDO的;如果有一个信号量规定了SEM_UNDO,那就要为其分配一个sem_undo数据结构,用来记录当前进程对每组信号量的债务,因此在task_struct中是有一个sem_undo结构队列的;每一个进程在记住欠谁债务的同时,还要记住有谁欠了它的债,因此在sem_array()中也有个指针undo,也是维持一个sem_undo队列;每一个sem_undo有两个指针分别用来链入到上述的两个队列中;使用的是alloc_undo来分配一个sem_undo并完成两个队列的链入;


(3)然后调用try_atomic_semop来试图将给定的所有信号量当做一个整体来完成;在操作这个for循环的时候,for正常结束,也就是对每个信号量的操作都没有使它的值semval变成负数的话,那就已经成功取得了所需的全部资源了;否则有三种情况使它break;首先,如果某个信号量的操作使其数值超过了最大的SEMVMX,本次系统调用已经支持不下去了,那就要转到out_of_range设置出错代码为ERANGE,再转到undo,通过一个while()循环将前面已经完成的操作也都抵消掉,若SEM_UNDO标志为1的话,还要将记账的资源也要还原的;第二种,是对某个信号量的操作使它变成了负数;这表示获取这个信号量代表的资源的努力受到了阻碍;一方面要根据IPC_NOWAIT标志函数的返回值;另一方面要通过undo处的while循环将已取得的资源全都退还;第三种,对某个信号量的操作sem_op的值为0,而这个信号量的当前值又是非0的,这种情况和第二种情况相同,也要使用IPC_NOWAIT来判断;返回值到sys_semop有三种情况,首先0表示所有的操作都成功了,负值表示出错了,到标号update那边处理一下即可;而返回值为1,表示某个信号量的操作失败了,需要睡眠等待;

(4)返回值大于1时,在semop()中,与报文队列类似,睡眠时要将代表着当前进程的sem_queue数据结构链入相应的sem_array数据结构中的sem_pending队列,根据alter是否改变,将其链入队列头还是尾,队列头的进程优先可以访问;如果本次信号量的值改变了,那就说明这个信号量集合发生了改变,原来因条件不满足等待的进程也许现在可以满足了,是通过update_queue()完成的;

(5)在update_queue()中,循环队列依次让每个正在睡眠中等待的进程试一下,看看能否完成其信号来那个的操作,还是通过try_atomic_semop()来完成的,最后一个参数表示只是试一下能不能成功,不执行真正的信号操作;其中有了信号量资源,q->status设置成1,或者出错了都是要将睡眠的进程唤醒的,q->status设置成出错码;由于发现q->status为1的都会跳过,找到一个可满足的进程就会返回了;从schedule()返回后,先通过sem_lock再次确认操作的对象仍是原先的信号集合,并将其锁住;若q->status为1,说明条件以满足了,但是还是要通过try_atomic_semop()再来检测;但是q->status不为1,此时可能是接收到信号而唤醒,也有可能是update_queue所设置的出错代码;

(6)对于最后的SEM_UNDO标志成1的,在exit()中有一个sem_exit(),如果exit()的进程的某个信号来那个在集合的队列中等待,将其移除队列,然后扫描该进程的semundo队列,根据每一个sem_undo数据结构的记载,依次对相应的信号量集合中的信号量数值做出调整,最后也是调用update_queue()唤醒可能在等待的进程;

(7)对于信号量的控制与管理,是在semctl()中完成的,与msgctl类似;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值