利用记录型信号量解决生产者消费者问题
时间: 2023-11-11 09:05:13 浏览: 81
生产者消费者问题是一个经典的计算机科学问题,解决的方法之一是使用记录型信号量。记录型信号量是一个具有计数器的信号量,它不仅可以阻止线程在尝试获取信号量时被阻止,还可以记录线程获取信号量的数量,从而可以用于解决生产者消费者问题。在这种情况下,一个生产者线程会增加信号量的计数器,表示有一个新项目可以消耗,而一个消费者线程则会减少信号量的计数器,表示消耗了一个项目。当计数器为零时,所有的消费者线程将被阻塞,因为没有可用的项目,而所有的生产者线程也将被阻塞,因为所有的项目都已经生产完毕。这样,可以保证生产和消费的平衡,从而避免一些问题,例如死锁和丢失项目。
相关问题
利用记录型信号量解决生产者消费者问题完整代码
下面是一个利用记录型信号量解决生产者消费者问题的完整代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#define BUFFER_SIZE 5 // 缓冲区大小
#define PRODUCER_NUM 2 // 生产者个数
#define CONSUMER_NUM 2 // 消费者个数
#define ITEM_NUM 10 // 生产的产品总数
int buffer[BUFFER_SIZE]; // 缓冲区
int in = 0; // 当前可插入位置
int out = 0; // 当前可消费位置
sem_t mutex; // 互斥信号量,用于保护缓冲区
sem_t full; // 计数信号量,表示缓冲区中可用的产品数
sem_t empty; // 计数信号量,表示缓冲区中空槽的数目
void *producer(void *arg) {
int id = *(int *)arg;
int item;
for (int i = 0; i < ITEM_NUM; i++) {
item = rand() % 100 + 1; // 随机生成一个产品
sem_wait(&empty); // 等待空槽
sem_wait(&mutex); // 保护缓冲区
buffer[in] = item; // 将产品放入缓冲区
printf("Producer %d produced item %d.\n", id, item);
in = (in + 1) % BUFFER_SIZE; // 更新插入位置
sem_post(&mutex); // 释放缓冲区
sem_post(&full); // 增加可用产品数
}
pthread_exit(NULL);
}
void *consumer(void *arg) {
int id = *(int *)arg;
int item;
for (int i = 0; i < ITEM_NUM; i++) {
sem_wait(&full); // 等待可用产品
sem_wait(&mutex); // 保护缓冲区
item = buffer[out]; // 从缓冲区取出一个产品
printf("Consumer %d consumed item %d.\n", id, item);
out = (out + 1) % BUFFER_SIZE; // 更新消费位置
sem_post(&mutex); // 释放缓冲区
sem_post(&empty); // 增加空槽数
}
pthread_exit(NULL);
}
int main() {
pthread_t producers[PRODUCER_NUM];
pthread_t consumers[CONSUMER_NUM];
int producer_ids[PRODUCER_NUM];
int consumer_ids[CONSUMER_NUM];
sem_init(&mutex, 0, 1); // 初始化互斥信号量
sem_init(&full, 0, 0); // 初始化计数信号量
sem_init(&empty, 0, BUFFER_SIZE); // 初始化计数信号量
// 创建生产者线程
for (int i = 0; i < PRODUCER_NUM; i++) {
producer_ids[i] = i + 1;
pthread_create(&producers[i], NULL, producer, &producer_ids[i]);
}
// 创建消费者线程
for (int i = 0; i < CONSUMER_NUM; i++) {
consumer_ids[i] = i + 1;
pthread_create(&consumers[i], NULL, consumer, &consumer_ids[i]);
}
// 等待生产者线程结束
for (int i = 0; i < PRODUCER_NUM; i++) {
pthread_join(producers[i], NULL);
}
// 等待消费者线程结束
for (int i = 0; i < CONSUMER_NUM; i++) {
pthread_join(consumers[i], NULL);
}
sem_destroy(&mutex); // 销毁互斥信号量
sem_destroy(&full); // 销毁计数信号量
sem_destroy(&empty); // 销毁计数信号量
return 0;
}
```
在该代码中,我们使用了三个信号量:互斥信号量 `mutex`、计数信号量 `full` 和 `empty`。其中,`mutex` 用于保护缓冲区,`full` 和 `empty` 分别表示缓冲区中可用的产品数和空槽的数目。
在生产者线程中,每次生成一个产品后,我们先等待 `empty` 信号量,表示缓冲区中有空槽,然后等待 `mutex` 信号量,保护缓冲区,将产品放入缓冲区,更新插入位置,最后释放 `mutex` 信号量和增加 `full` 信号量,表示可用产品数增加了一个。
在消费者线程中,每次取出一个产品后,我们先等待 `full` 信号量,表示缓冲区中有可用的产品,然后等待 `mutex` 信号量,保护缓冲区,从缓冲区中取出一个产品,更新消费位置,最后释放 `mutex` 信号量和增加 `empty` 信号量,表示空槽数增加了一个。
在 `main` 函数中,我们先初始化三个信号量,然后创建生产者和消费者线程,最后等待线程结束,销毁信号量。
注意,在实际开发中,我们应该使用 `pthread_mutex_t` 和 `pthread_cond_t` 来实现互斥和条件变量,这样会更加灵活和高效。
编写利用记录型信号量解决生产者消费者问题代码
我们可以使用信号量实现生产者消费者问题。
示例代码如下:
```
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
sem_t empty, full;
pthread_mutex_t mutex;
int buffer[10];
int fill = 0;
int use = 0;
void put(int value) {
buffer[fill] = value;
fill = (fill + 1) % 10;
}
int get() {
int tmp = buffer[use];
use = (use + 1) % 10;
return tmp;
}
void *producer(void *arg) {
int i;
for (i = 0; i < 100; i++) {
sem_wait(&empty);
pthread_mutex_lock(&mutex);
put(i);
printf("Producer: %d\n", i);
pthread_mutex_unlock(&mutex);
sem_post(&full);
}
pthread_exit(NULL);
}
void *consumer(void *arg) {
int i, tmp = 0;
while (tmp != -1) {
sem_wait(&full);
pthread_mutex_lock(&mutex);
tmp = get();
printf("Consumer: %d\n", tmp);
pthread_mutex_unlock(&mutex);
sem_post(&empty);
}
pthread_exit(NULL);
}
int main() {
pthread_t pid, cid;
sem_init(&empty, 0, 10);
sem_init(&full, 0, 0);
pthread_mutex_init(&mutex, NULL);
pthread_create(&pid, NULL, producer, NULL);
pthread_create(&cid, NULL, consumer, NULL);
pthread_join(pid, NULL);
pthread_join(cid, NULL);
sem_destroy(&empty);
sem_destroy(&full);
pthread_mutex_destroy(&mutex);
return 0;
}
```
在这个示例代码中,我们定义了一个大小为10的循环缓冲区(buffer)。生产者通过put函数向缓冲区添加数据,消费者通过get函数从缓冲区取出数据。
empty信号量表示空闲的缓冲区数量,full信号量表示已填充的缓冲区数量。如果缓冲区已满,生产者会等待empty信号量,如果缓冲区已空,消费者会等待full信号量。
使用互斥锁(mutex)来保证对缓冲区的访问是互斥的,避免多个线程同时访问缓冲区导致数据错误。
主函数中创建生产者线程和消费者线程,等待它们完成后销毁信号量和互斥锁。
希望这个示例代码能够帮到您。
阅读全文