我记得刚学操作系统原理的时候,第一次接触到P-V操作,感觉好难懂喔!尤其是进行P(sem)操作时,将sem值减1,若sem 的值为负数,则调用P操作的进程暂停执行,直到另一个进程对同一个信号量做V操作;V(sem)操作的作用是将信号量sem值加1,若sem的值小于等于0,从相应对了中选择一个进程,唤醒它。这当中让我最迷糊的就是sem的值为0时,进行P、V操作会如何执行下去?
这问题一直困扰我好久,今天我才明白,我忽略了一个细节问题:进行P或V操作后,进程该如何执行是根据sem值进行减1或加1后的值判断的。也就是说,进行P-V操作,那么我们就可以根据减1或加1后的sem值判断:
sem =0
若是P(sem)操作,则调用P操作的进程则继续执行;
若是V(sem)操作,则调用V操作的进程先唤醒该信号量上的进程,然后返回原进程继续执行或转进程调度;
sem > 0
若是P(sem)操作,则调用P操作的进程则继续执行;
若是V(sem)操作,则调用V操作的进程继续执行;
sem < 0
若是P(sem)操作,则调用P操作的进程则进入等待状态,在相应队列中排队,然后转向系统的进程调度;
若是V(sem)操作,则调用V操作的进程先唤醒该信号量上的进程,然后返回原进程继续执行或转进程调度。
当信号量sem小于0是,其绝对值表示系统中因请求该类资源未被满足而被阻塞的进程数量,sem 大于0是表示可用的临界资源数量。
而在Linux/Unix里面的POSIX (Portable Operating System interface of Unix) 的无名信号量中,有几个函数:
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value); // 创建信号量,并初始化其值为value,pshared为是否允许进程间信号量共享,由于目前Linux还没实现,所有pshared设置为0
int sem_wait(sem_t *sem);
int sem_tyrwait(sem_t *sem);
int sem_post(sem_t *sem);
int sem_getvalue(sem_t *sem); //获取信号量的值
int sem_destroy(sem_t *sem); //销毁信号量
sem_wait() 和sem_post()相当于P操作和V操作,只不过sem_wait()调用阻塞当前进程直到信号量的值大于0,函数返回是信号量减1;sem_post()将信号量加1同时发出信号唤醒等待的进程。 sem_tyrwait() 和sem_wait()相同,不过不阻塞当前进程,当信号量的值为0时,返回EAGAIN表示以后重试。
编译包含上面几个函数的程序,要加 -lrt, 以连接librt.so库。