详解C语言进程同步机制

2020-06-17 19:22:43王振洲

​有一点需要注意的,因为原语是将多个指令合并成一个指令,在原语的执行过程中也是不响应中断的,使之成为原子操作,这个期间,等于是屏蔽中断,也就等价于我们讲的第一种硬件方式—关中断,因此原语操作的指令长度应该是短小精悍的,这样才能保证系统的效率。

​利用上述的硬件指令能有效的实现进程的互斥,但是当资源忙碌时,其他访问进程的必须不断的进程测试,处于一种“忙等”的状态,违背了让权等待的原则,造成处理机时间的浪费,同时也很难将它们用于解决复杂的进程问题。

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);
 }
}