进程同步---生产者与消费者问题以及进程同步机制--信号量及P、V操作

进程同步 synchronization

描述

指系统中多个进程中发生的时间存在某种时序关关系,需要相互合作,共同完成一项任务。


场景

一个进程运行到某一点时,要求另一个伙伴进程为它提供消息,在未获得消息之前,该进程进入阻塞态,获得消息后被唤醒进入就绪态。*

生产者与消费者问题又称为有界缓冲区问题

场景:

  • 一个或者多个生产者生产某种类型的数据放置在缓冲区中
  • 有消费者从缓冲区中取数据,每次取一项
  • 只能有一个生产者货消费者对缓冲区进行操作

要解决的问题:

  • 当缓冲区已满时,生产者不会继续向其中添加数据
  • 当缓冲区为空时,消费者不会从中移走数据
  • 要避免忙等待,睡眠和唤醒操作(原语)
#define N 100
int count = 0;
void producer(void)
{
    int item;
    while(TRUE)
    {
        item = produce_item();
        if(count == N)         /*判断缓冲区是否满了*/
            sleep();
        insert_item(item);
        count = count + 1;
        if(count == 1) /*判断是否有消费者睡眠*/
            wakeup(consumer);
    }
}

void consumer(void)
{
    int item;
    while(TRUE)
    {
        if(count == 0) /*判断是否有数据*/
            sleep();
        item = remove_item();
        count = count - 1;
        if(count == N-1) /*判断是否有生产者睡眠*/
            wakeup(producer);
        consume_item(item);
    }
}

一种经典的进程同步机制–信号量及P、V操作

信号量及P、V操作

  • 一个特殊变量
  • 用于进程间传递信息的一个整数值
  • 定义
struct semaphore
{
    int count;
    queueType queue;
}
  • 信号量说明: semaphore s;
  • 对信号量可以实施的操作:初始化、P和V(P、V是指荷兰语中的test(porberen)和increment(verhogen))
    • P、V操作为原语操作(Primitive or atomic action)
    • 在信号量上定义了三个操作初始化(非负数)、P操作、V操作
    • 最初提出的是二元信号量(解决互斥)之后推广到一般信号量(多值)或计数信号量(解决同步)
P(s)
{
    s.count--;
    if(s.count < 0)
    {
        该进程状态置为阻塞状态;
        该进程插入相应的等待队列s.queue末尾;
        重新调度;
    }
}

V(s)
{
    s.count++;
    if(s.count <= 0)
    {
        唤醒相应的等待队列s.queue中等待的一个进程;
        改变其状态为就绪态,并将其插入就绪队列;
    }
}

用PV操作解决进程间的互斥问题

  • 分析并发进程的关键活动,或定临界区
  • 设置信号量 mutex,初值为1
  • 在临界区前实施P(mutex)
  • 在临界区之后实施V(mutex)

用信号量解决生产者、消费者问题

#define N 100                   /*缓冲区个数*/
typedef int semaphore;          /*信号量是一种特殊的整数类型*/
semaphore mutex = 1;            /*互斥信号量:控制对临界区的访问*/
semaphore empty= N;             /*空缓冲区的个数*/
semaphore full = 0;             /*满缓冲区个数*/
void producer(void)
{
    int item;
    while(TRUE)
    {
        item = produce_item()
        P(&empty);
        P(&mutex);
        insert_item(item);
        V(&mutex);
        V(&full);

    }

}

void consumer(void)
{
    int item;
    while(TRUE)
    {
        P(&full);
        P(&mutex);
        item = remove_item()
        P(&mutex);
        V(&empty);
        consume_item(item);
    }

}

producer中P(&empty);P(&mutex);中不能颠倒位置会造成死锁问题。consumer中的V(&mutex);V(&full);V操作位置可以颠倒,不会出错,但是现在最好,还有consume_item(item);放在临界区内也行,不会出错,但是会增加临界区的发威,现在这种排序的临界区范围最小。

你可能感兴趣的:(笔记,基础知识复习)