1965年,荷兰学者Dijkstra提出的信号量(Semaphores)机制是一种卓有成效的进程同步工具。在长期且广泛的应用中,信号量机制又得到了很大的发展,它从整型信号量经记录型信号量,进而发展为“信号量集”机制。现在,信号量机制已经被广泛地应用于单处理机和多处理机系统以及计算机网络中。
下文是记录型信号量:
在整型信号量机制中的wait操作,只要是信号量S<=0,就会不断测试。因此,该机制并未遵循“让权等待”准则,而是使进程处于“忙等”状态。记录型信号量机制则是一种不存在“忙等”现象的进程同步机制。
但在采取了“让权等待”的策略后,又会出现多个进程等待访问同一个临界资源的情况。为此,在信号量机制中,除了需要一个用于代表资源数目的整型变量value外,还应该增加一个进程链表指针L,用于链接上述的所有等待进程。记录型信号量是由于它采用了记录型的数据结构而得名的。
数据结构:
1 2 3 4 5 |
typedef struct { int value; struct process *L; } semaphore; |
这里的value和上面的S含义相同,都表示可用的资源数目。
链表L表示的是就绪队列,因此核心仍是PV,只不过如何对待进程,记录型信号量的做法更加完善。解决了让进程忙等的现象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void P(semaphore s) { s.value--; // 申请资源,边界是value已经为0了,那么现在变-1,表示有一个进程在等待 if(s.value < 0) { 将此进程加入就绪队列,等待; block(s.L); } } void V(semaphore s) { s.value++; if(s.value <= 0) { 将进程P从就绪队列中移出; wakeup(P);// 唤醒 } } |
当s.value = 0时,是从s.value = -1时候变过来的,因此,虽然s.value = 0了,还不能忘了把最后一个进程移出就绪队列并叫醒它。
链表L表示的是阻塞队列,不是就绪队列