zl程序教程

您现在的位置是:首页 >  其他

当前栏目

16-用信号量实现进程互斥,同步,前驱关系

同步进程 实现 关系 16 互斥 信号量
2023-06-13 09:14:07 时间

信号量机制实现进程互斥

主要步骤

  1. 分析并发进程的关键活动,划定临界区(例如:对打印机等临界资源的访问就应放在临界区内)
  2. 设置互斥信号量,常命名为mutex,初值为1(因为一般情况下对临界区的访问同一时间只能存在一个进程)
  3. 在临界区之前执行P(mutex)
  4. 在临界区之后执行V(mutex)

示例

semaphore mutex=1;
P1(){
    ...
    P(mutex)
    临界区代码段...
    V(mutex)
    ...
}

P2(){
    ...
    P(mutex)
    临界区代码段...
    V(mutex)
    ...
}

注意

  • 对不同的临界资源需要设置不同的互斥信号量(mutex1,mutex2)
  • P,V操作必须成对出现,缺少P就不能保证临界资源的互斥访问,缺少V就会导致资源永远不被释放,等待进程永远不能唤醒

信号量机制实现进程同步

进程同步的目的在于让各个本来异步并发的进程按要求有序推进

P1(){
    代码1;
    代码2;
    代码3;
}

P2(){
    代码4;
    代码5;
    代码6;
}

例如,在上面的P1和P2进程中,由于异步性导致程序执行顺序并不确定,但我们必须保证代码1和代码2在代码4之前执行,此时就需要使用进程同步机制实现

用信号量实现进程同步的步骤

  1. 分析什么地方需要实现“同步关系”,即保证“一前一后”执行的两个操作
  2. 设置同步信号量:S,初值为0
  3. 在“必须先执行的操作”之后执行V(S)
  4. 在“必须后执行的操作”之前执行P(S)

示例

semaphore S=0; //初始化同步信号量,初值为0

P1(){
    代码1;
    代码2;
    //代码1和代码2是必须先执行的操作
    //所以在它们之后执行V(S)
    V(S); 
    代码3;
}

P2(){
    //代码4是必须后执行的操作
    //所以在它前面执行P(S)
    P(S);
    代码4;
    代码5;
    代码6;
}

若先执行了P1进程,执行完代码1和代码2后,进行V操作,则信号量S++后S=1,之后执行P2进程时,执行P操作判断S=1>0所以表示有可用资源可以继续执行,S–后S=0,不会执行block原语被阻塞,可以继续往下执行代码4

若先执行P2进程,由于P操作判断S=0表示没有可用资源,所以执行block原语,主动请求阻塞P2进程,直到P1进程执行完代码1和代码2后到V操作发现S=-1表示等待队列中有进程在等待资源,所以其主动唤醒P2进程,P2进程得以继续执行代码4

信号量机制实现前驱关系

一共有六个进程P1,P2…P6,其中进程P1中有代码S1,P2中有代码S2,…P6中有代码S6,这些代码要求按如下前驱图所示的顺序执行

主要步骤

其实每一对前驱关系都是一个进程同步问题(需要保证一前一后的操作),所以

  1. 要为每一对前驱关系各设置一个同步变量
  2. 在“必须先执行操作”之后对相应同步变量执行V操作
  3. 在“必须后执行操作”之前对相应同步变量执行P操作

不难看出,前驱关系本质上还是更复杂的进程同步问题