临界资源
对于某些资源来说,其在同一时间只能被一个进程占用。这些一次只能被一个进程占用的资源就是所谓的临界资源。典型的临界资源比如物理上的打印机,或者是存在硬盘或内存中被多个进程所共享的一些变量和数据等,如果这类资源不被看成是临界资源加以保护,那么就有可能造成丢数据的问题。
临界区
对于临界资源的访问,必须要互斥的进行。也就是说当临界资源被一个资源占用的时候,另一个申请该临界资源的进程会被阻塞,指导其所申请的临界资源被释放。而进程而内访问临界区资源的代码被成为临界区。
对于临界资源的访问的过程可以分为四个部分:
1.进入区:首先要查看临界区是否可以访问,如果可以访问,则转到步骤二,否则进程会被阻塞
2.临界区:在临界区,对资源进行操作
3.退出区:清除临界区被占用的标志
4.剩余区:进程与临界区不相关部分的代码
进程同步
进程同步指得是两个或者多个进程,为完成某种任务需要按照一定的次序进行,比如生产者和消费者的问题中,如果生产者生产的资源为0,那么消费者也就没有资源可以消费,所以生产者和消费者存在着同步的关系。
进程互斥
进程互斥是进程之间的间接制约关系,当一个进程进入临界资源时,另一个进程必须等待。只有当使用临界资源的进程退出临界区后,这个进程才会解除阻塞状态。
产生死锁的条件
1.互斥条件
2.一个进程在占用资源,同时请求新的资源并且不释放已经占用的资源
3.不可剥夺条件:进程已经获得资源,在进程结束之前不能强制剥夺资源
4.循环等待条件:若干进程之间形成一种头尾相接的循环等待条件
进程如果要产生死锁四个条件必须全部满足
通过信号量机制实现进程互斥
//定义信号量由开关和等待执行的进程的集合组成我们在这里称其为等待队列
struct semaphore{
int count;
queueType queue;
}
//定义判断是否可以执行进程的机制,如果信号量count>0则可以执行,否则进入等待队列
void semWait (semaphore s){
s.count--;
if(s.count<0){
place this process in s.queue;
block this process;
}
}
//释放刚刚占用的资源,如果此时完全没有可以用的资源则从等待队列里释放一个进程执行
void semSignal(semaphore s){
s.count++;
if(s.count <=0){
remove a process P from s.queue;
place process on ready list;
}
}
执行的过程
const int n=/*number of processes */;//这里是进程的数量
semaphore s=1;//信号量
void p(int i){
while(true){
semWait(s);//首先判断是否可以访问临界区
//进入临界区对资源进行操作
/* critical section */
semSignal(s);
/*remainder*/
}
}
void main(){
parbegin(P(1),P(2),.....,P(n));
}
结论
1.如果s.value的值为正,则表示对进程进行阻塞之前可用的资源的的实际数目;2.若s.value的值为负,则其绝对值表示阻塞队列中s.queue中的等待进程的个数;3.每次的wait()操作,意味着请求一个单位的该类资源,是系统中的可以分配的该类资源数减少一个,每一次的signal()操作,表示执行进程释放一个单位资源,是系统中的可以供分配的该类资源数增加一个。
生产者消费者问题
错误的例子,对于全局变量n没有互斥使用
binary_semaphore a.s=1;
binary_semaphore a.delay=0;
void producer(){
while(true){
produce();
semWaitB(s);
append();
n++;
if(n==1)semSignalB(delay);
semSignalB(s);
}
}
void consumer(){
semWaitB(s);
take();
n--;
semSignalB(s);
consume();
if(n==0)semWaitB(delay);
}
void main(){
n=0;
parbegin(producer,consumer);
}
正确的例子
binary_semaphore a.s=1;
binary_semaphore a.delay=0;
void producer(){
while(true){
produce();
semWaitB(s);
append();
n++;
if(n==1)semSignalB(delay);
semSignalB(s);
}
}
void consumer(){
int m;/*a local variable*/
semWaitB(s);
take();
n--;
m=n;
semSignalB(s);
consume();
if(m==0)semWaitB(delay);
}
void main(){
n=0;
parbegin(producer,consumer);
}