详解C语言进程同步机制

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

我们在软件同步机制里讲的两个例子,都是在落锁和判断之间发生中断,乃至导致无法实现互斥的进入临界区,那么,我们是不是可以在这个期间不允许发生中断呢?这个就需要用到硬件了,下面我们就一起来看一下。

3.1 关中断

这个方法就非常之霸气了,进程在落锁和判断之间不是有可能会发生中断么,那么我在开始测试之前关闭中断(OS内核不响应中断信号),到测试并上锁之后在打开中断。这样可以保证两个操作之间的连续性,保证临界资源的互斥访问。

​但是关中断也必然会存在许多缺点:1.滥用关中断的权利可能导致严重后果;2.关中断时间过长会影响系统的并发性,直接的影响系统的资源利用率;3.关中断无法适应多CPU系统(多CPU系统不在本文的讨论范围内)

3.2 测试并建立(Test-and-Set, TS)指令

我们使用关中断来解决落锁和判断之间不允许响应中断,但是我们如果把这两个执行变成一条指令呢,这样是不是就可以保证中断不会再落锁和判断之间被响应?

​我们可以借助一条硬件指令-----“测试并建立”指令TS(Test-and-Set),来实现临界资源的互斥访问。TS指令的一般性描述如下:

//TS指令
boolean TS(boolean *lock){
 if(*lock == false){
  *lock = true;
  return true;
 }else{
  return false;
 }
}

//内存中保存的锁的值
boolean lock;
lock = false; //临界区可以进入

//进程P1,P2,P3...Pn
process Pi{
 //...
 while(!TS(&lock));//循环请求锁
 临界区;
 lock = false;//解锁,归还临界资源
 
}

我们可以把TS指令看成上面的TS函数的执行过程,其执行过程是不可分割的,即是一条原语。当lock的值为false时,表示临界资源空闲,当lock的值为true时,表示该资源正在被使用。

​使用TS指令来管理临界区时,需要为每个临界资源设置一个布尔变量lock。当有进程需要进入临界区时,需要先用TS指令测试临界区对应的那把“锁”,如果返回true,临界区空闲,可以进入,并落锁,阻止别的进程再进入临界区;如果TS返回false,则必须要循环请求,直到TS返回的值变为true。

3.3 对换指令

该指令也称为swap指令,用于交换两个字的内容,其处理过程描述如下:

void swap(boolean *a, boolean *b){
 boolean tmp;
 tmp = *a;
 *a = *b;
 *b = tmp;
}

//内存中保存的锁的值
boolean lock;
lock = false; //临界区可以进入

//进程P1,P2,P3...Pn
process Pi{
 //...
 boolean key = true;
 do{
  swap(&lock, &key);
 }while(key != false)//循环请求锁
 临界区;
 lock = false;//解锁,归还临界资源
}

Swap指令和TS指令类似,也需要为每个临界资源设置一个布尔变量lock,不同的在进程中使用一个局部变量Key字段去替换出lock中的值,通过判断key的值就可以判断临界资源是否空闲。