我通过使用线程和信号量来分配生产者和消费者问题。任务是允许用户定义生产者的#,消费者的#和缓冲区大小。如果生产者到达buffersize,程序总是锁定。但是要求说如果生产者达到缓冲区,则消费者线程应该从缓冲区开始并从中获取内容。我不知道如何解决这个问题,老师拒绝帮忙。我是C语言的初学者,请给我一些建议。非常感谢你
我的程序可以在Producer = Consumer或Producer<消费者,生产者除外>缓冲区大小,它似乎出现死锁,我想我理解其中的原因,但我不知道如何修复代码让Consumer线程首先运行而不是返回到Producer线程。
当producer = 3 consumer = 1且buffersize = 2
时,这是运行结果./Task2 3 1 2
Producer 0 has started
Producer 0:Put item 0.
Producer 1 has started
Producer 1:Put item 1.
Producer 2 has started
要求说结果应该是
Started
Producer 0 has started
Producer 0: Put item 0.
Producer 1 has started
Producer 1: Put item 1.
Producer 2 has started
Consumer 0 has started
Consumer 0: Taked item 0.
Producer 2: Put item 2.
Terminated!
这是我的原始代码,我已经丢弃了一些输入错误检查代码
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
pthread_t *pid, *cid;
void *producer(void *param);
void *consumer(void *param);
void init();
int Remove();
struct prot_buffer{
int Producer;
int Consumer;
int *buffer;
int buffersize;
int front;
int rear;
int item;
sem_t mutex;
sem_t slots;
sem_t items;
}b;
main(int argc, char *argv[]){
int c1;
b.Producer = atoi(argv[1]);
b.Consumer = atoi(argv[2]);
b.buffersize = atoi(argv[3]);
init();
pid = (pthread_t *)malloc(b.Producer *sizeof(pthread_t));
cid = (pthread_t *)malloc(b.Consumer *sizeof(pthread_t));
for (c1=0; c1< b.Producer; c1++){
printf("Producer %d has started\n", c1);
pthread_create(&(pid[c1]),NULL, producer, NULL);
pthread_join(pid[c1], NULL);
printf("Producer %d:Create item %d.\n", c1,c1);
}
/* Create the consumer threads */
for (c1=0; c1<b.Consumer; c1++){
printf("Consumer %d has started\n", c1);
pthread_create(&(cid[c1]),NULL, consumer, NULL);
if (b.front==b.rear){
printf("Terminated!\n");
exit(0);
}
pthread_join(cid[c1], NULL);
printf("Consumer %d:Taked item %d.\n", c1, c1);
}
free(b.buffer);
free(pid);
free(cid);
sem_destroy(&b.items);
sem_destroy(&b.slots);
sem_destroy(&b.mutex);
printf("Threads terminated!\n");
exit(0);
}
void *producer(void *param){
sem_wait(&b.slots); sem_wait(&b.mutex);
if(b.rear<=b.buffersize){
b.buffer[b.rear] = b.item;
b.rear++;
sem_post(&b.mutex); sem_post(&b.items);
}else{
sem_post(&b.mutex); sem_post(&b.items); }
}
void *consumer(void *param){
Remove();
}
void init(){
b.buffer = (int *) malloc(b.buffersize *sizeof(int));
b.buffersize = b.buffersize;
b.front = b.rear =0;
sem_init(&b.items, 0, 0);
sem_init(&b.slots,0,b.buffersize);
sem_init(&b.mutex, 0, 1);
}
int Remove(){
sem_wait(&b.items);
sem_wait(&b.mutex);
b.item = b.buffer[b.front];
b.front++;
sem_post(&b.mutex);
sem_post(&b.slots);
return b.item;
}
我的新代码
main(int argc, char *argv[]){
...
pthread_create(&pid,NULL, producer, NULL);
pthread_create(&cid,NULL, consumer, NULL);
....
}
void *producer(void *param){
int c2;
for (c2=0; c2 < b.Producer; c2++) {
printf("Producer %d has started\n", c2);
b.item = c2;
sem_wait(&b.slots);
sem_wait(&b.mutex);
b.buffer[b.rear] = b.item;
b.rear = (b.rear+1)%b.buffersize;
printf("Producer %d:Put item %d.\n", c2,c2);
sem_post(&b.mutex);
sem_post(&b.items);
}
return NULL;
}
void *consumer(void *param){
int c2;
for (c2=0; c2 < b.Consumer; c2++) {
printf("Consumer %d has started\n", c2,c2);
b.item = c2;
sem_wait(&b.items);
sem_wait(&b.mutex);
b.buffer[b.front] = b.item;
b.front = (b.front+1)%b.buffersize;
printf("Consumer %d:take item %d.\n", c2, c2);
sem_post(&b.mutex);
sem_post(&b.slots);
}
return NULL;
}
为了避免学校出现问题,我删除了一些代码和一些描述。
现在程序结果正确,谢谢你的帮助。在这种情况下,我使用b.item作为变量来显示缓冲区内的项目,但错误。使用其他变量如前或后也不起作用。
计划结果 -
生产者= 2,消费者= 2,缓冲区= 2
./F 2 2 2
started
Producer 0 has started
Producer 0:Put item 0.
Producer 1 has started
Producer 1:Put item 1.
Consumer 0 has started
Consumer 0:Take item 0.
Consumer 1 has started
Consumer 1:Take item 1.
1 item(s) left in the buffer! //This is wrong!
Terminated!
生产者= 3,消费者= 1,缓冲区= 2
./F 3 1 2
started
Producer 0 has started
Producer 0:Deposited item 0.
Producer 1 has started
Producer 1:Deposited item 1.
Producer 2 has started
Consumer 0 has started
Consumer 0:Removed item 0.
Producer 2:Deposited item 2.
0 item(s) left in the buffer! //Still wrong!
Terminated!
生产者= 2,消费者= 5,缓冲区= 3
./F 2 5 3
started
Producer 0 has started
Producer 0:Put item 0.
Producer 1 has started
Producer 1:Put item 1.
Consumer 0 has started
Consumer 0:Take item 0.
Consumer 1 has started
Consumer 1:Take item 1.
Consumer 2 has started
2 item(s) left in the buffer! //Wrong again!
Terminated!
答案 0 :(得分:2)
您的缓冲区大小为2.前两个生成器填满此缓冲区。因此,第三个是等待消费者拿一个项目,以便它可以添加到缓冲区。 但是生产者循环中的pthread_join
永远不允许创建消费者! pthread_join
暂停main
进程,直到第3个生成器终止。因此,第三个Producer中的死锁无限期地等待缓冲区被永不到来的消费者释放。
我建议你仔细阅读本文的Exercise 3,其中涉及与您完全相同的问题和相同的数据结构。他们清楚地阐明了如何防止缓冲区溢出,在哪里打印生产者数据。可能是它为毕业生提供的标准信号量教程练习。
答案 1 :(得分:0)
您的信号量的初始化和使用似乎是正确的 - 它们是生产者 - 消费者队列的自然选择 - 它是不是的条件,(condvars没有计数,因此即使您的操作系统不支持,也需要while循环才能正确操作)虚假的唤醒功能)。
然而,你对缓冲区的使用似乎有点“关闭”。我认为缓冲区应该是循环的?如果是这样,只要前面或后面的索引到达数组的末尾,就应该将索引设置回0。您应该在生产者和消费者代码中的互斥锁内执行此操作。检查索引应该只是将它们重置为缓冲区的开头,不应该以任何方式改变信号量信号/等待的操作。
那,你似乎在创建线程后立即加入线程。通常,为了测试/演示生产者/消费者操作,不会不断创建线程,立即加入线程(以便构造线程必须立即等待),然后离开以终止。运行一些生产者和消费者线程更为常见,这些线程循环,不断产生/消费消息,(可能是一个非常短的睡眠循环 - 一些开发人员认为没有有效用途并且是反模式的那种循环)。 / p>
持续创建/终止/销毁线程非常浪费,并且会在测试代码中导致几乎所有开销和非常少的生产者/消费者执行的应用程序。
最后一件事 - 不要在没有考虑它的情况下加入线程一两秒钟。它可能不是最佳的,它可能没有必要,它可能是一个障碍,它可能是一场灾难。如果连接只是为了让你的主线程(以及进程)保持提前终止,那么最好找另一种方法 - 等待键盘输入或使用长期sleep()循环。