1.生产者消费者问题(信号量) 参考教材中的生产者消费者算法,创建5个进程,其中两个进程为生产者进程,3个进程为消费者进程。一个生产者进程试图不断地在一个缓冲中写入大写字母,另一个生产者进程试图不断地在缓冲中写入小写字母。3个消费者不断地从缓冲中读取一个字符并输出。为了使得程序的输出易于看到结果,仿照的实例程序,分别在生产者和消费者进程的合适的位置加入一些随机睡眠时间。 可选的实验:在上面实验的基础上实现部分消费者有选择地消费某些产品。例如一个消费者只消费小写字符,一个消费者只消费大写字母,而另一个消费者则无选择地消费任何产品。消费者要消费的产品没有时,消费者进程被阻塞。注意缓冲的管理。C语言实现,尽量不要用指针,提供思路和源代码,以及总结
时间: 2024-02-15 21:06:09 浏览: 76
思路:
本题考察了生产者-消费者问题,我们可以使用信号量来解决该问题。我们需要创建一个缓冲区,包含一个大小为N的字符数组和两个指针,一个指向缓冲区的队首,一个指向缓冲区的队尾。使用两个信号量,一个表示缓冲区空的数量,一个表示缓冲区满的数量。生产者进程将会在缓冲区满的时候被阻塞,消费者进程将会在缓冲区空的时候被阻塞。
具体步骤如下:
1. 初始化信号量和缓冲区,将队首和队尾指针都初始化为0。
2. 创建5个进程,其中2个进程为生产者进程,3个进程为消费者进程。
3. 生产者进程不断地往缓冲区中写入大写或小写字符,每次写入一个字符,然后释放一个空缓冲区信号量,如果缓冲区已满,则进程被阻塞。
4. 消费者进程不断地从缓冲区中读取一个字符,并输出该字符,每次读取一个字符,然后释放一个满缓冲区信号量,如果缓冲区为空,则进程被阻塞。
5. 可选实验:部分消费者有选择地消费某些产品。我们可以在消费者进程中添加一个判断条件,如果该消费者只消费小写或大写字符,则只读取相应的字符,否则读取任意字符。
6. 当所有进程都执行完毕后,释放信号量和清空缓冲区。
源代码:
```
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#define N 10 // 缓冲区大小
#define PRO_NUM 2 // 生产者数量
#define CON_NUM 3 // 消费者数量
sem_t full, empty; // 满缓冲区和空缓冲区信号量
char buffer[N]; // 缓冲区
int front = 0, rear = 0; // 队首和队尾指针
void *producer(void *arg) {
while (1) {
// 生产一个字符
char c;
if (*((int *)arg) == 1) {
c = 'A' + rand() % 26; // 大写字母
} else {
c = 'a' + rand() % 26; // 小写字母
}
// 等待空缓冲区
sem_wait(&empty);
// 写入到缓冲区
buffer[rear] = c;
rear = (rear + 1) % N;
printf("Producer %d produces %c\n", *((int *)arg), c);
sleep(rand() % 3); // 随机睡眠
// 释放满缓冲区信号量
sem_post(&full);
}
}
void *consumer(void *arg) {
while (1) {
// 等待满缓冲区
sem_wait(&full);
// 从缓冲区读取一个字符
char c = buffer[front];
front = (front + 1) % N;
// 判断是否只读取小写或大写字母
if (*((int *)arg) == 1 && c < 'a') {
sem_post(&full);
continue;
} else if (*((int *)arg) == 2 && c >= 'a') {
sem_post(&full);
continue;
}
printf("Consumer %d consumes %c\n", *((int *)arg), c);
sleep(rand() % 3); // 随机睡眠
// 释放空缓冲区信号量
sem_post(&empty);
}
}
int main() {
// 初始化信号量和缓冲区
sem_init(&full, 0, 0);
sem_init(&empty, 0, N);
// 创建生产者和消费者线程
pthread_t pro_threads[PRO_NUM], con_threads[CON_NUM];
int pro_ids[PRO_NUM] = {1, 2};
int con_ids[CON_NUM] = {1, 2, 3};
int i;
for (i = 0; i < PRO_NUM; i++) {
pthread_create(&pro_threads[i], NULL, producer, &pro_ids[i]);
}
for (i = 0; i < CON_NUM; i++) {
pthread_create(&con_threads[i], NULL, consumer, &con_ids[i]);
}
// 等待所有线程执行完毕
for (i = 0; i < PRO_NUM; i++) {
pthread_join(pro_threads[i], NULL);
}
for (i = 0; i < CON_NUM; i++) {
pthread_join(con_threads[i], NULL);
}
// 释放信号量和清空缓冲区
sem_destroy(&full);
sem_destroy(&empty);
front = 0;
rear = 0;
return 0;
}
```
总结:
本题考察了生产者-消费者问题和信号量的使用。通过使用信号量来管理缓冲区,实现了多个生产者和消费者进程的同步和互斥访问。同时,本题的可选实验扩展了原有问题,增加了挑战性。
阅读全文