有一点需要注意的,因为原语是将多个指令合并成一个指令,在原语的执行过程中也是不响应中断的,使之成为原子操作,这个期间,等于是屏蔽中断,也就等价于我们讲的第一种硬件方式—关中断,因此原语操作的指令长度应该是短小精悍的,这样才能保证系统的效率。
利用上述的硬件指令能有效的实现进程的互斥,但是当资源忙碌时,其他访问进程的必须不断的进程测试,处于一种“忙等”的状态,违背了让权等待的原则,造成处理机时间的浪费,同时也很难将它们用于解决复杂的进程问题。
4.信号量机制
信号量机制是1965年迪杰斯特拉(Edsger Wybe Dijkstra)提出的一种卓有成效的进程同步工具。信号量机制在长期的应用中得到了很大的发展,从整型信号量经记录型信号量,进而发展为“信号量集”机制,在目前来讲,信号量。
需要着重说明的一点是:信号量除了初始化外,仅能被通过两个标准的原子操作wait(S)和signal(S)来访问,这两个操作也被称为P、V操作,这几个操作都是原语操作。
4.1 整型信号量
整型信号量是最开始由迪杰斯特拉定义的,整型信号量也很简单,里面只有一个表示资源的数量的整形量,一般使用S符号来表示,整型信号量下的wait和signal操作可描述如下:
//整型信号量定义
int S;
//P操作
wait(S){
while(S<=0);
S--;
}
//V操作
signal(S){
S++;
}
因为wait和signal操作是原子的,因此他们在执行的过程中是不可被中断的。也就是说当一个进程在修改某个信号量时,没有其他的进程可以同时对该信号量进行修改。
需要注意的是,整型信号量的wait操作,只要是信号量S<=0,就会不断的测试,让进程处于一种“忙等”的状态,没有遵循让权等待的原则。还有就是,把信号量的初值置为1,表示只允许一个进程访问临界资源,此时的信号量就可以转换为互斥信号量,用于完成进程的互斥(对所有的信号量机制都是一样)。
4.2 记录型型号量
为了解决整型信号量存在的忙等问题,应当采取让权等待原则。但是又会出现一个新的问题,如果多个进程并发请求访问临界资源,除了第一个抢到了信号量外,其余的进程都应该释放处理机,但是这些等待的进程要如何保存呢?为此,除了wait操作需要遵循让权等待原则,还需在信号量中增加一个进程的链表指针list,用与链接上面描述的多个等待访问临界资源的进程。也因为记录了等待的进程,这种信号量集之被称为记录型信号量。
记录型信号量具体的描述以及对应的wait和signal操作如下所示:
//记录型信号量定义
typedef struct{
int value;
struct process_control_block *list;
}semaphore;
//P操作
wait(semaphore *S){
S->value--;
if(s->value < 0) {
block(S->list);
}
}
//V操作
signal(semaphore *S){
S->value++;
if(S->value <= 0){
wakeup(S->list);
}
}










