进程互斥(mutual exclusion)——软件算法方式

Peterson算法

适用于两个进程之间的互斥

//i j 是两个进程的id
#define i 0 
#define j 1

//flag[] 数组 进入临界区意愿标记,每个进程都有自己的意愿,所以要两个。
//turn   变量 第二标记,只有当两个进程都有意愿时,
//           就需要这个。可以理解成迟到标志。注意条件。
//~~~~~~~~~~~~~~~~~~~~上锁
flag[i] = true;  //打标记给另一个进程看,表明我打算进临界区啦。
turn = i;        //先签到,turn指向的后来者。
while(flag[j] && turn == i); 
//1、另一个进程是否也有意愿;
//2、自己是否是后来者;
//如果两个条件都满足就等吧。

//~~~~~~~~~~~~~~~~~~~~临界区

//~~~~~~~~~~~~~~~~~~~~开锁
flag[0] = false;//离开了临界区,当然要解除自己的意愿咯。方便另一个进程进入。

问题1:如何更好的理解turn变量的作用?
  如果没有turn变量肯定是错误的。如果去除,那么在两个进程同时表明进入临界区的意愿时,会导致两个进程都进不入临界区。
  turn变量只有在两个进程都有意愿的时候,才能启到控制流量的作用。可以将turn理解成迟到标记,当然这种理解要结合while循环里的turn==i条件。同样也可以将turn理解成早到标志,这样的话就要将while循环里的turn==j改成turn==j。

面包店算法

有限个进程之间的互斥
定义伪代码(a, b) < (c, d)等价于(a

#define n 10 //最大进程数
//choosing[] 数组 进程是否取号
//num[] 数组 进程取得的号码 0表示未取号
//~~~~~~~~~~~~~~~~~~~~上锁
choosing[i] = true;
//取号码,取到的号码可能会相同。
num[i] = max(num[0],...,num[n-1])+1;
choosing[i] = false;
for(j = 0 ; j < n ; j++){
  while(choosing[j]);
  while( num[j]!=0 && (num[j],j) < (num[i],i) );
//1、存在同样已取号的进程;
//2、存在号码比自己小的进程。
//   或者当最小的号码和自己相同时,自己的id比同号的大。
//同时满足两个条件时,则等待。
}

//~~~~~~~~~~~~~~~~~~~~临界区

//~~~~~~~~~~~~~~~~~~~~开锁
num[i] = 0;

问题1:为什么只要从头开始for循环遍历一遍就可以了?如果等待过程中前面再次取号会怎么样?

  因为假如对于进程i,遍历到k时,小于k的进程加入取到的号码一定是大于进程i的号码,所以对于进程i来说就不需要考虑了。如图所示:


进程互斥(mutual exclusion)——软件算法方式_第1张图片
面包店算法1

  当两个进程取到相同的号码时,在一开始就会建立好等待关系。如图所示


进程互斥(mutual exclusion)——软件算法方式_第2张图片
面包店算法2.png

总结

  两个算法有一个共同的思路:在进入临界区之前,都是先标记自己想进入临界区的意愿,在退出临界区后取消标记。
  每个进程都是只在乎自己,在标记的时候,不会去考虑别人,所以这个时候就有可能有多个进程同时标记自己的意愿。解决方法都是人为规定一个执行顺序
  例如:Peterson算法是按谁先抢到旗帜(turn变量),就谁先执行,另一个则等待。
  面包店算法是也是按照谁先取号,就谁先执行。由于不对号码进行保护,所以可能会出现相同的号码,这个时候按照进程id号的大小进行排序。

你可能感兴趣的:(进程互斥(mutual exclusion)——软件算法方式)