如果有三个进程R、WW1、WW2共享一个缓冲器B,而B中每次只能存放个数。当缓冲器中无数时,进程R可以将从输入设备上迹入的数存放到缪冲器中。若存放到缓冲哭中的是奇数,则允许进程W1将其取出打印,若在放到缓冲器中的是偶数,则允许进程W2将其取出打印。同的规定,进程R必须等缓冲区中的数被取出打印后才能再存放1个数,进程w1或W2对每次存入缓冲器的数只能打印一次,W1和W2都不能从缓冲中取数。写出这三个并发进程能正确工作的程序,并带有注释
时间: 2024-03-05 15:54:40 浏览: 87
以下是一个使用信号量实现的解决方案,使用三个信号量分别表示缓冲器的空槽位、缓冲器的占用槽位、缓冲器中奇数的数量:
```c
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 10
int buffer[BUFFER_SIZE];
int count = 0;
sem_t empty, full, odd;
void *producer(void *arg) {
int num;
while (1) {
num = rand() % 100;
sem_wait(&empty); // 等待空槽位
buffer[count++] = num;
printf("Producer produces %d\n", num);
if (num % 2 == 0) {
sem_post(&full); // 发信号量通知W2
} else {
sem_post(&odd); // 发信号量通知W1
}
}
}
void *consumer_odd(void *arg) {
while (1) {
sem_wait(&odd); // 等待奇数
sem_wait(&full); // 等待占用槽位
int num = buffer[--count];
printf("Consumer odd prints %d\n", num);
sem_post(&empty); // 发信号量通知R
}
}
void *consumer_even(void *arg) {
while (1) {
sem_wait(&full); // 等待占用槽位
int num = buffer[--count];
printf("Consumer even prints %d\n", num);
sem_post(&empty); // 发信号量通知R
}
}
int main() {
srand(time(NULL));
sem_init(&empty, 0, BUFFER_SIZE);
sem_init(&full, 0, 0);
sem_init(&odd, 0, 0);
pthread_t tid_producer, tid_consumer_odd, tid_consumer_even;
pthread_create(&tid_producer, NULL, producer, NULL);
pthread_create(&tid_consumer_odd, NULL, consumer_odd, NULL);
pthread_create(&tid_consumer_even, NULL, consumer_even, NULL);
pthread_join(tid_producer, NULL);
pthread_join(tid_consumer_odd, NULL);
pthread_join(tid_consumer_even, NULL);
sem_destroy(&empty);
sem_destroy(&full);
sem_destroy(&odd);
return 0;
}
```
解释:
- 进程R作为生产者,不断产生随机数,并将其存入缓冲器中。
- 进程W1和W2分别作为两个消费者,不断从缓冲器中取出数,如果是奇数就打印,如果是偶数就打印。
- 信号量`empty`表示缓冲器中空槽位的数量,一开始为`BUFFER_SIZE`,每次生产者存入一个数时,就会将它减1,代表空槽位减少一个;每次消费者取出一个数时,就会将它加1,代表空槽位增加一个。如果`empty`为0,生产者就会阻塞等待;如果`empty`不为0,生产者就会继续执行。
- 信号量`full`表示缓冲器中已占用的槽位数量,一开始为0,每次生产者存入一个数时,就会将它加1,代表占用槽位增加一个;每次消费者取出一个数时,就会将它减1,代表占用槽位减少一个。如果`full`为0,消费者就会阻塞等待;如果`full`不为0,消费者就会继续执行。
- 信号量`odd`表示缓冲器中奇数的数量,一开始为0,每次生产者存入一个数时,如果它是奇数,就会将`odd`加1;每次W1消费者取出一个奇数时,就会将`odd`减1。如果`odd`为0,W1消费者就会阻塞等待;如果`odd`不为0,W1消费者就会继续执行。
- 生产者在存入数之前,必须先等待信号量`empty`,如果没有空槽位,就会阻塞等待;如果有空槽位,就会将`empty`减1,代表空槽位减少一个。
- 生产者在存入数之后,会判断这个数是奇数还是偶数,并根据判断结果发送不同的信号量。如果是偶数,就发送信号量`full`,通知W2消费者;如果是奇数,就发送信号量`odd`,通知W1消费者。
- W1和W2消费者在取出数之前,都必须等待信号量`full`,如果没有占用槽位,就会阻塞等待;如果有占用槽位,就会将`full`减1,代表占用槽位减少一个。
- W1消费者在取出奇数之前,必须先等待信号量`odd`,如果没有奇数,就会阻塞等待;如果有奇数,就会将`odd`减1,代表奇数数量减少一个。
- 每次生产者存入数或消费者取出数时,都要通过信号量`empty`或`full`发出通知,告诉其他线程缓冲器的状态发生了变化。如果有线程因为等待信号量而阻塞,就会被唤醒,继续执行。
- 由于缓冲器中的数据是共享的,因此需要使用信号量来保护共享资源,避免竞争条件的发生。同时,由于生产者和消费者之间的关系比较复杂,所以需要使用多个信号量来进行同步。
阅读全文