电子科技大学考研题目:
M个生产者进程和 N个消费者进程共享大小为 K 的缓冲区,遵循规则如下:
(1) 进程之间必须以互斥方式访问缓冲区;
(2) 对每 1 条放入缓冲区的数据,所有消费者都必须接收 1 次;
(3) 缓冲区满时,生产者必须阻塞;
(4) 缓冲区空时,消费者必须阻塞。
请用 P、V 操作实现其同步过程,须说明信号量含义。
分析,根据规则:
规则一,进程间互斥访问缓冲区,K个缓冲区需要 K 个信息量,初始化时缓冲区是可以访问的。
规则三,缓冲区满时,生产者需要阻塞,也就是当前每个缓冲区占用时,生产者阻塞。只要有空缓冲区生产者就可以生产,因为生产者不能等待某个具体的缓冲区,需要设置一个初始值为 K 的信号量来控制生产者是否能够进行生产。
规则二、四是实现对消费者的阻塞,只要控制每个消费者的消费数即默认实现了规则四。
因为每个消费者都要读一遍数据,所以生产每生产一个产品需要增加所有消费者的消费量,另外需要设置一个消费者是否读取数据的计数矩阵,以确定最后一个数据读取者读完数据量,增加生产者可以缓冲区数。
写了一段代码如下,未仔细验证仅供参考:
semaphore buff_mutex[K] = {1}; // 缓冲区 0~K 读写信号量
semaphore empty_mutex = K; // 空缓冲区信号量, 0-缓冲区满,生产者互斥
semaphore read_mutex[M] = {0}; // 消费者可用消息数信号量
buffer buffer[K] = {NULL};
bool buff_read[K][M] = {1}; // 初始化每个消费者每个缓存位置都读过
producer()
{
int i,j;
while (1) {
// 实现满队列等待
P(empty_mutex);
for(i=0; i<K; i++){
// 实现写进程的互斥
P(buff_mutex[i]);
if(buffer[i] == NULL){
buffer[i] = get_new_message();
for(j=0; j<M; j++){
// 置每个消息未读取
buff_read[i][j]=0;
// 增加每个消费者消息数,激活消费者
V(read_mutex[j]);
}
}
V(buff_mutex[i]);
sleep(random(1)); // 随机等待以调度其它生产者
}
}
}
consumer(no) // no 是消费者编号
{
int i,j;
buffer read_message;
while(1){
read_message = NULL;
// 消费者有消息读取
P(read_mutex[no]);
for(i=0; i<K; i++){
P(buff_mutex[i]);
if(buffer[i][no] == 0){
read_message=buffer[i] // 读取消息
buff_read[i][no] = 1
for(j=0; j<M; j++){
// 判断是否全读消费者都读取消息
if(buffer[i][j] == 0){
break;
}
}
if(j>=M){ // 所有消费者读完信息
buffer[i] = NULL;
V(empty_mutex); // 激活生产者
}
}
V(buff_mutex[i]);
if(read_message){
// 读到消息了,跳出循环,保证未读消息数量正确
break;
}
}
}
}