闪电龟龟--笔记

万物寻其根,通其堵,便能解其困。
  博客园  :: 新随笔  :: 管理

PV操作

Posted on 2018-11-30 16:45  闪电龟龟  阅读(971)  评论(0编辑  收藏  举报

什么是原语?

  答:执行时不可中断的过程。

P操作P(s):将整形型号量s的值减去1,如果结果小于0,那么调用P(s)的进程,将进程的信号量s的等待状态。

V操作V(s):将整形信号量s的值减去1,如果结果大于0,那么释放一个等待信号量s的进程。

/* 关于P操作 */
void P(semaphore *s){
    s->value = s->value - 1;
    if(s->value < 0){
        insert(CALLER, s->PCB);  /* 将调用进程插入到等待信号量s的进程队列中 */
        block(CALLER);  /* 堵塞调用进程 */
    }
}
/* 关于V操作 */
void V(semaphore *s){
    PID proc_id;  /* 执行的进行号 */
    s->value = s->value + 1
    if(s->value <= 0){
    remove(s->PCB, &proc_id);  /* 从等待信号量s的进程中摘除proc_id该进程 */
    wakeup(proc_id);  /* 唤醒该进程 */
    }
}

值得注意的是:pv执行时,唤醒的顺序是由系统决定,唤醒的顺序不会影响程序正确性。

 

PV操作实现进程同步的操作

执行步骤:

  1.为各进程设置私有信号量;2.为私有信号量赋初值;3.根据pv操作以及私有信号量设置各进程的执行顺序。

那问题来了:什么是私有信号量?

  答:私有信号量:各进程发送的用于控制进程同步的消息。公有信号量:用于进程的互斥信号量。

  二者的区别:私有信号量只与制约和被制约的进程有关,与整组并发进程无关。

 

经典案列:现有m个生产者和n个消费者,它们共享可存放k件物品的缓冲区。

int buffer[k];  /* 设置缓冲区以及容量 */
semaphore s1, s2, s;  /* 设置信号量:s1(当进程缓冲区满时,生产者不能往满的缓冲区执行放操作的信号量),s2(当进程的缓冲区空时,消费者不能往空的缓冲区执行取操作的信号量), s(生产者与消费者互斥的信号量) */
int in, out;  /* 设置存储的操作(说白了就是存放的位置) */
/* 赋初值 */
s.value = 1;
s1.value = k;
s2.value = 0;
Cobegin
    repeat produceri;  /* 生产者的执行 */
    repeat consumerj;  /* 消费者的执行 */
Coend;
/* 生产者进程 */
process produceri{
    int item;
    生产者存放一件产品到item中;
    P(&s1);  /* 执行P操作,检查是否能够进行放操作 */
    P(&s);  /* 执行P操作,检查临界区是能能够进入 */
    buffer[in] = item;  /* 将产品放到buffer缓冲区中 */
    in = (in + 1) % k;  /* 往后移动一位 */
    V(&s2);  /* 执行V操作 */
    V(&s);  /* 执行V操作 */
}
/* 消费者进程 */
process consumerj{
    int item;
    P(&s2);  /* 执行P操作,检查是否能够进行取操作 */
    P(&s);  /* 执行P操作,检查临界区是能能够进入 */
    item = buffer[out];  /* 取一件产品 */
    out = (out + 1) % k;
    V(&s1);
    V(&s);
    消费产品;
}