在Unix信号量机制实现之前,通常采用加锁文件的方法。信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。
其它想进入该关键代码段的线程必须等待直到***个线程释放信号量。为了完成这个过程,需要创建一个信号量VI,然后将Acquire Semaphore VI以及Release Semaphore VI分别放置在每个关键代码段的首末端。确认这些信号量VI引用的是初始创建的信号量。
系统调用semop用来对Unix信号量集合中的一个或多个信号量进行操作,操作命令由用户提供的操作结构数组来定义,该结构如下:
- struct sembuf{
- short sem_num; /*信号量在集合中的下标*/
- short sem_op; /*操作值*/
- short sem_flg; /*操作标志*/
- };
系统从用户地址空间读Unix信号量操作结构数组,并核实信号量下标的合法性及进程是否具备读或修改信号量所必需的权限。若权限不够则调用失败;若进程必须睡眠,则它将已操作过的信号量恢复为该系统调用开始时的值,然后它就睡眠,直到它等待的事件发生时再重新执行该系统调用。
由于系统将操作数组保存在一个全局数组中,因此若它必须重新执行该调用的话,它必须重新从用户空间读该数组。这样,操作按原语方式执行--或一次做完或根本不做。
系统根据操作值来改变信号量的值:
①若操作值为正,系统就增加信号量的值并唤醒所有等待信号量增值的进程;
②若操作值是0,系统就检查信号量的值:如果为0,就继续数组中的其它操作;否则把等待信号量的值为0的睡眠进程数加1,然后睡眠;
③若操作值为负且其绝对值不超过信号量的值,系统就把操作值(一个负数)加到信号量值上,如果结果为0则系统就唤醒所有等待信号量的值为0的睡眠进程;
④若信号量的值小于操作值的绝对值,系统就让进程睡眠在"等待信号量增值"这一事件上。
当进程在Unix信号量操作过程中睡眠时,它睡眠在可中断级上,因此当它接收到软中断信号时就被唤醒了。用户可在操作标志中设置IPC_NOWAIT标志以防止进程睡眠。
如果进程执行了一个信号量操作,锁住了某些资源,却没有恢复信号量的值就退出了(如收到kill信号),那么就可能出现危险情况。为了避免这类问题,用户可在操作标志中设置SEM_UNDO标志。当进程退出时,系统便撤除该进程做过的每个信号量操作的影响。
值得指出的是,当你使用两个或多个Unix信号量时,死锁总是可能的,系统并不能检查多个信号量间的死锁。
本文所用算法及调用格式均已在SCOUNIX3.2、SCOOpenSever3.X及5.X上运行通过。
【编辑推荐】