现在你是linux专家请用C语言完成以下题目:使用条件变量实现生产者-消费者问题 1商品使用一个链式队列描述初始商品个数为8最大商品个数是10个不同的商品用不同的随机数区分 2生产者有3个线程每个线程每3秒产生一个商品 3 消费者有2个线程先睡眠5秒每个线程每1秒消耗一个商品 显示每次生产和消费的商品的随机编号。
由于题目涉及到线程和条件变量的操作,需要使用多线程库 pthread.h,以下是一个可能的实现:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#define MAX_ITEMS 10
#define PRODUCER_NUM 3
#define CONSUMER_NUM 2
struct item {
int id;
struct item *next;
};
struct queue {
struct item *head;
struct item *tail;
int num_items;
pthread_mutex_t lock;
pthread_cond_t not_full;
pthread_cond_t not_empty;
};
int get_random_id() {
return rand() % 1000; // 随机数区间 [0, 999]
}
void *producer(void *arg) {
struct queue *q = (struct queue *) arg;
while (1) {
sleep(3);
pthread_mutex_lock(&q->lock);
while (q->num_items == MAX_ITEMS) {
pthread_cond_wait(&q->not_full, &q->lock);
}
struct item *new_item = malloc(sizeof(struct item));
new_item->id = get_random_id();
new_item->next = NULL;
if (q->num_items == 0) {
q->head = new_item;
} else {
q->tail->next = new_item;
}
q->tail = new_item;
q->num_items++;
printf("Producer %ld: produced item %d\n", pthread_self(), new_item->id);
pthread_cond_signal(&q->not_empty);
pthread_mutex_unlock(&q->lock);
}
return NULL;
}
void *consumer(void *arg) {
struct queue *q = (struct queue *) arg;
sleep(5); // 先睡眠5秒
while (1) {
sleep(1);
pthread_mutex_lock(&q->lock);
while (q->num_items == 0) {
pthread_cond_wait(&q->not_empty, &q->lock);
}
struct item *item_to_consume = q->head;
q->head = item_to_consume->next;
q->num_items--;
if (q->num_items == 0) {
q->tail = NULL;
}
printf("Consumer %ld: consumed item %d\n", pthread_self(), item_to_consume->id);
free(item_to_consume);
pthread_cond_signal(&q->not_full);
pthread_mutex_unlock(&q->lock);
}
return NULL;
}
int main() {
srand(time(NULL)); // 初始化随机数种子
struct queue q = {
.head = NULL,
.tail = NULL,
.num_items = 8, // 初始商品个数为8
.lock = PTHREAD_MUTEX_INITIALIZER,
.not_full = PTHREAD_COND_INITIALIZER,
.not_empty = PTHREAD_COND_INITIALIZER
};
pthread_t producer_threads[PRODUCER_NUM];
pthread_t consumer_threads[CONSUMER_NUM];
for (int i = 0; i < PRODUCER_NUM; i++) {
pthread_create(&producer_threads[i], NULL, producer, &q);
}
for (int i = 0; i < CONSUMER_NUM; i++) {
pthread_create(&consumer_threads[i], NULL, consumer, &q);
}
for (int i = 0; i < PRODUCER_NUM; i++) {
pthread_join(producer_threads[i], NULL);
}
for (int i = 0; i < CONSUMER_NUM; i++) {
pthread_join(consumer_threads[i], NULL);
}
return 0;
}
代码中使用了一个结构体 queue 来描述商品队列,其中包含了队列头和尾指针、当前队列中商品个数、互斥锁和两个条件变量。生产者线程的主要逻辑是每隔3秒产生一个商品,如果队列已满就等待条件变量 not_full,否则将新的商品加入队列,并发送条件变量 not_empty 通知消费者线程,最后释放互斥锁。消费者线程的主要逻辑是每隔1秒消耗一个商品,如果队列为空就等待条件变量 not_empty,否则从队列头取出一个商品并释放相应的内存,然后发送条件变量 not_full 通知生产者线程,最后释放互斥锁。
需要注意的是,由于生产者和消费者线程访问队列需要互斥,所以需要使用互斥锁 lock 来保护队列。同时,每个条件变量 not_full 和 not_empty 对应一个互斥锁,这是因为条件变量的等待和发送操作必须在互斥锁的保护下进行,否则可能出现竞态条件。在代码中,等待条件变量的操作使用了 pthread_cond_wait 函数,它会自动释放互斥锁并进入等待状态,直到被相应的条件变量发送通知并重新获得互斥锁。发送条件变量的操作使用了 pthread_cond_signal 函数,它会唤醒一个等待该条件变量的线程,如果有多个等待线程,只有其中一个会被唤醒,其他线程继续等待。
原文地址: http://www.cveoy.top/t/topic/bvWS 著作权归作者所有。请勿转载和采集!