信号量机制的实际使用-第二十九天

2024-01-02 15:23:40

目录

回顾旧知

实现进程互斥

实现进程同步

实现进程的前驱关系

本节思维导图


回顾旧知

1、一个信号量对应一种资源

2、信号量的值 = 该种资源的剩余数量(信号量值小于0,说明此时有进程在等待这种资源)

3、P(S):申请一个资源S,如果资源不够就阻塞等待

4、V(S):释放一个资源S,如果有进程在等待该资源,则唤醒一个进程

实现进程互斥

实现步骤:

  1. 并发进程的关键活动(单核处理机情况下各进程轮流访问访问临界区),划定临界区(如:对临界资源打印机的访问就应放在临界区)
  2. 设置互斥信号量mutex,初始值为1(mutex表示“进入临界区的名额”)
  3. 在进入区P(mutex):申请资源
  4. 在退出区V(mutex):释放资源

注意事项:

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

/*记录型信号量的定义*/
typedef struct
{
    int value;          //剩余资源数
    struct process *L;  //等待队列
}semaphore;

/*信号量机制实现互斥*/
semaphore mutex = 1;    //初始化信号量

P1()
{
...
P(mutex);        //使用临界资源前需要加锁
临界区代码段...
V(mutex);        //使用临界区资源后需要解锁
...
}

P2()
{
...
P(mutex);        //使用临界资源前需要加锁
临界区代码段...
V(mutex);        //使用临界区资源后需要解锁
...
}

实现进程同步

进程同步:令各并发进程按要求有序的推进(让本来异步并发的进程互相配合,有序推进)

异步性的体现:若分配给P1进程的时间片只允许该进程执行完自己的代码1和代码2,然后就要为P2进程分配时间片,若该时间片只允许该进程执行完自己的代码4,然后就要为P1进程分配......,这就导致代码段的执行顺序是未知的

实现步骤:

  1. 分析什么地方需要实现“同步关系”(必须保证“一前一后”执行的两个操作或两句代码)
  2. 设置同步信号量S,初始值为0(信号量S表示“某种资源”)
  3. 在“前操作”之后执行V(S)
  4. 在“后操作”之前执行P(S)

(前V后P)

/*信号量机制实现同步*/
semaphore S = 0;    //初始化同步信号量,初始值为0

P1()
{
    代码1:
    代码2;
    V(S);   //释放资源
    代码3;
}

P2()
{
    P(S);   
    代码4:
    代码5;
    代码6;
}

关于如何保证“代码4(后操作)一定是在代码2(前操作)之后执行”的解释:

  1. 若先执行到V(S)操作,则S++后S=1。之后执行到P(S)操作时,由于S=1,表示有可用资源,会执行S--,S的值变为0,P2进程不会执行block原语,而是继续向下执行代码4
  2. 若先执行到P(S)操作,由于S=0,S--后会S=-1,表示此时没有可用资源,因此P操作中会执行block原语,主动请求阻塞。之后当执行完代码2(时间片用完),继而执行V(S)操作,S++,使S变回0,由于此时有进程在该信号量对应的阻塞队列中,因此会在V操作中执行wakeup原语,唤醒P2进程。这样P2就可以继续执行代码4了
  3. 信号量S代表“某种资源”,刚开始是没有这种资源的,P2需要使用这种资源,而又只能由P1产生这种资源

实现进程的前驱关系

本节思维导图

~over~

文章来源:https://blog.csdn.net/m0_73975164/article/details/135336713
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。