DJ2-5 生产者-消费者问题
创始人
2025-06-01 02:11:51

生产者与消费者是一个广义的概念,可以代表一类具有相同属性的进程。

生产者和消费者进程共享一个大小固定的缓冲区,其中,一个或多个生产者生产数据,并将生产的数据存入缓冲区,并有一个消费者从缓冲区中取数据。

假设缓冲区的大小为n(存储单元的个数),它可以被生产者和消费者循环使用

分别设置两个指针in和out,指向生产者将存放数据的存储单元和消费者将取数据的存储单元,如图

生产者-消费者执行流程图

1. 利用记录型信号量解决生产者-消费者问题

变量定义、所需函数及主程序如下:

typedef struct {int value;struct process_control_block * list;
} semaphore;int in = 0;
int out = 0;
semaphore mutex, empty, full;    
mutex->value = 1;       //由于缓冲池是一种临界资源,因此使用互斥型信号量
empty->value = n;       //代表空缓冲区的数量,最初存储单元均为空
full->value = 0;        //代表满缓冲区的数量,最初存储单元均为空void producer();        //生产者进程
void consumer();        //消费者进程void main() {cobegin     //并发执行producer(); consumer();coend
}

wait() 和 signal() 描述如下:

wait(semaphore * S) {S->value--;if(S->value < 0) block(S->list);//S->value == 0时代表刚好取走最后一个资源
}signal(semaphore * S) {S->value++;if(S->value <= 0) wakeup(S->list);//S->value == 0时代表刚好还有一个进程被阻塞
}

 生产者进程如下:

void producer() {do {//produce an item in nextpwait(&empty);    //判断是否有空存储单元wait(&mutex);    //判断是否可用缓冲池buffer[in] = nextp;in = (in + 1) % n;signal(&mutex);  //唤醒一个使用者signal(&full);   //唤醒一个消费者} while(true);
}

消费者进程如下:

void producer() {do {wait(&full);     //判断是否有空存储单元wait(&mutex);    //判断是否可用缓冲池nextc = buffer[out];out = (out + 1) % n;signal(&mutex);  //唤醒一个使用者signal(&empty);  //唤醒一个消费者//consume the item in nextc} while(true);
}

1)wait(&mutex) 必须放在 wait(&full) 后面,避免抢占到了缓冲池的使用权,结果发现没有空存储单元可用,从而导致资源浪费。

2)mutex 是互斥型信号量,因此对其的 wait 和 signal 操作必须成对出现。

3)进程一旦被阻塞,不管这个时间片是否用完,都立即进入下一个时间片。

plus. 举例说明

t1t2t3t4t5t6t7t8t9
runningc1: wait(full)

p1: item->nextp

p1: wait(empty)

p1: wait(mutex)

p2: item->nextp

p2: wait(empty)

p2: wait(mutex)

p3: item->nextp

p3: wait(empty)

p1: CS

p1: signal(mutex)

p1: signal(full)

finish

p2: CS

p2: signal(mutex)

p2: signal(full)

finish

c1: wait(mutex)

c1: CS

c1: signal(mutex)

c1: signal(empty)

finish

p3: wait(mutex)

p3: CS

p3: signal(mutex)

p3: signal(full)

finish

full->value0-1=-1(<0?)-1+1=0(<=0?)0+1=1(<=0?)1+1=2(<=0?)
full->list{c1}wakeup(full->list){}{}
empty->value2-1=1(<0?)1-1=0(<0?)0-1=-1(<0?)-1+1=0(<=0?)
empty->list{}{}{p3}wakeup(empty->list)
mutex->value1-1=0(<0?)0-1=-1(<0?)-1+1=0(<=0?)0+1=1(<=0?)1-1=0(<0?)0+1=1(<0?)

1-1=0(<0?)

0+1=0(<=0?)

mutex->list{}{p2}wakeup(mutex->list){}{}{}{}
ready{p1, p2, p3}{p2, p3, p1}{p3, p1}{p1}{p2, c1}{c1}{}{p3}{}

 

 

 

 

相关内容

热门资讯

秦安莲花干馍:百年传承的非遗美... 🌾 你是否曾经在记忆的长河中,嗅到那股熟悉的麦香?在腊月的秦安县莲花镇,清水河畔的街巷里,传统的味道...
原创 团... 年夜饭的餐桌上,总少不了几道带着记忆温度的老味道。今年我特意整理了六道南北通吃的家常菜,从软糯的年糕...
原创 早... 标题:早餐这样吃,可比油条省事多了,无需揉面无需造型,又营养又好吃。 在忙碌的早晨,我们总是渴望一...
原创 2... 众所周知,中国有南北地区之分,每个地方因为地理环境的差异,在饮食文化方面也有很大的区别,就像大部分南...
告别宴客焦虑:学会这八道压箱底... 招待客人时,总担心饭菜不够丰盛、不够美味,搞得自己焦虑不堪。别愁啦!今天就为你奉上八道压箱底硬菜的详...