C 单一生产者和多消费者
我尝试使用这样一种场景:生产者向缓冲区(state.value)生成一个值,多个使用者读取缓冲区并在数组中更新它。下面是代码C 单一生产者和多消费者,c,linux,multithreading,pthreads,producer-consumer,C,Linux,Multithreading,Pthreads,Producer Consumer,我尝试使用这样一种场景:生产者向缓冲区(state.value)生成一个值,多个使用者读取缓冲区并在数组中更新它。下面是代码 #include <pthread.h> #include <stdio.h> #include <stdlib.h> pthread_mutex_t mutex; pthread_cond_t prod, cons; static int count = 0; struct
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
pthread_mutex_t mutex;
pthread_cond_t prod, cons;
static int count = 0;
struct shared_state{
int done;
int value;
int value_available;
int *array;
int j;
}state;
void * producer(void *arg){
int a[] = {12,11,10,9,8,7};
int size = sizeof(a)/sizeof(a[0]);
int i = 0;
while(i<size){
pthread_mutex_lock(&mutex);
while(state.value_available)
pthread_cond_wait(&prod, &mutex);
state.value = a[i++];
printf("In producer: %d\n",state.value);
state.value_available = 1;
pthread_cond_signal(&cons);
pthread_mutex_unlock(&mutex);
}
state.done = 1;
count++;
printf("Producer count: %d\n",count);
pthread_exit(NULL);
}
void * consumer(void *arg){
while(!(state.done)){
pthread_mutex_lock(&mutex);
while(!state.value_available)
pthread_cond_wait(&cons,&mutex);
state.array[(state.j)] = state.value;
printf("In consumer: %d\t%d\n",state.array[state.j], state.j);
(state.j)++;
state.value_available = 0;
pthread_cond_signal(&prod);
pthread_mutex_unlock(&mutex);
}
int i;
for(i=0;i<6;i++)
printf("%d-->",state.array[i]);
printf("\n");
count++;
printf("Consumer count: %d\n",count);
}
int main(void){
state.done = 0;
pthread_t pro,con,con2;
state.value_available = 0;
state.j = 0;
state.array = (int *)malloc(sizeof(int)*6);
pthread_create(&pro, NULL, producer, (void *)NULL);
pthread_create(&con, NULL, consumer, (void *)NULL);
pthread_create(&con2, NULL, consumer, (void *)NULL);
pthread_join(pro,NULL);
pthread_join(con,NULL);
pthread_join(con2,NULL);
pthread_exit(NULL);
printf("\n");
return 0;
}
首先,无法初始化互斥体和条件变量。因为它们是全局的,所以它们的初始状态并不是因为这个原因而不确定的,但也不一定是有效的。必须使用适当的初始化函数,或使用用于初始化宏的初始化函数。比如说,
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t prod = PTHREAD_COND_INITIALIZER;
pthread_cond_t cons = PTHREAD_COND_INITIALIZER;
你似乎在这个问题上很幸运,但这并不意味着你不应该解决它
第二,不检查函数调用的返回值是否有错误代码。要使代码健壮,您确实必须这样做。错误发生的原因既有代码中断,也有不受控制的运行时问题,如果您认为函数调用总是成功的,那么您迟早会遇到麻烦
但是,您还有一个更大的问题:pthread\u cond\u signal()
会唤醒一个在给定条件变量上等待的线程(如果确实有线程在等待)。当生产者最后一次向CV发送信号时,两个使用者线程都可能被阻塞。在这种情况下,一个唤醒并执行其处理,但另一个保持阻塞状态。因为使用者在从等待中醒来后会对条件谓词执行正确的检查,所以可以使用pthread\u cond\u broadcast()
来解决该问题
但这只是解决方案的一半。因为您确实执行了正确的谓词检查,而且因为使用者将更新共享状态,使其自己的谓词在释放互斥之前为false,所以第二个使用者只要从等待中醒来,就会恢复等待。此外,如果不继续轮候,又会怎样呢?它没有可供消费的价值,也没有可供选择的路径
底线:
- 您的制作人必须向消费者的简历进行广播,而不是向其发出信号,至少在制作完最后一个产品之后
- 当消费者从等待CV中醒来时,它不仅必须检查值是否可用,还必须检查生产者是否完成。在这两种情况下,它都不能恢复等待,但只有当一个值实际可用时,它才能使用该值
pthread_*()
调用)。这是免费调试!函数中:main():由于此行:pthread_exit(NULL)代码>,以下几行:printf(“\n”)
和返回0代码>将永远不会执行。线程:consumer()
缺少(干净编译和正确执行顺序所必需的)pthread\u退出(NULL)要获得干净的编译,每个线程主体中的第一行需要处理传递的参数。最简单的方法是在每个线程中插入以下行作为第一行:(void)arg
谢谢John。在结合state.done和broadcast之后,我可以毫不费力地解决它。
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t prod = PTHREAD_COND_INITIALIZER;
pthread_cond_t cons = PTHREAD_COND_INITIALIZER;