问题
I made a circular buffer with multiple clients writing (in the end I want them to write messages of different size) into a buffer. The server reads them out. It's based on the code in a consumer/producer problem:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#define BUFFER_SIZE 10
struct cBuf{
char *buf;
int size;
int start;
int end;
pthread_mutex_t mutex;
pthread_cond_t buffer_full;
pthread_cond_t buffer_empty;
};
struct cBuf cb;
void buf_Init(struct cBuf *cb, int size) {
int i;
cb->size = size + 1;
cb->start = 0;
cb->end = 0;
cb->buf = (char *)calloc(cb->size, sizeof(char));
}
void buf_Free(struct cBuf *cb) {
free(cb->buf);
}
int buf_IsFull(struct cBuf *cb) {
return (cb->end + 1) % cb->size == cb->start;
}
int buf_IsEmpty(struct cBuf *cb) {
return cb->end == cb->start;
}
int buf_Insert(struct cBuf *cb, char *elem) {
int i,j;
pthread_mutex_lock(&(cb->mutex));
for (i=0; i < strlen(elem); ++ i){
if (buf_IsFull(cb)==1) printf("\nProducer (buf_Insert) is waiting ");
while(buf_IsFull(cb)){
pthread_cond_wait(&(cb->buffer_empty),&(cb->mutex));
}
cb->buf[cb->end] = elem[i];
cb->end = (cb->end + 1) % cb->size;
printf("%c-",elem[i]);
}
pthread_cond_signal(&(cb->buffer_full));
pthread_mutex_unlock(&(cb->mutex));
return 0;
}
int buf_Read(struct cBuf *cb, char *out) {
int i,j;
pthread_mutex_lock(&(cb->mutex));
if (buf_IsEmpty(cb))printf("\nConsumer (buf_Read) is waiting ");
while(buf_IsEmpty(cb)){
pthread_cond_wait(&(cb->buffer_full),&(cb->mutex));
}
for (i=0;i<BUFFER_SIZE-1;i++){
if (cb->start == cb->end) break;
out[i] = cb->buf[cb->start];
cb->buf[cb->start] = '_';
cb->start = (cb->start + 1) % cb->size;
printf("%c-",out[i]);
}
pthread_cond_signal(&(cb->buffer_empty));
pthread_mutex_unlock(&(cb->mutex));
return 0;
}
void * client(void *cb){
pthread_detach(pthread_self());
struct cBuf *myData;
myData = (struct cBuf*) cb;
char input[]="Hello World!";
if (buf_Insert(myData, input)) printf("\n");
return 0;
}
int main(void) {
char out[60];
pthread_t thread;
int i;
pthread_cond_init(&(cb.buffer_full),NULL);
pthread_cond_init(&(cb.buffer_empty),NULL);
buf_Init(&cb, BUFFER_SIZE);
for (i = 0; i<1; i++){
if(pthread_create (&thread,NULL, client, (void *) &cb) !=0){
#ifdef DEBUG
printf("\nDEBUG (Main Thread) - Error while creating thread");
#endif
} else {
#ifdef DEBUG
printf("\nDEBUG (Main Thread) - Thread created");
#endif
}
}
while (1){
if (buf_Read(&cb,out)) printf ("succes");
}
buf_Free(&cb);
return 0;
}
It mostly works when the buffer is bigger than the message of a single client (by making buffer_size
bigger, e.g., 16). When I make it smaller, however, it seems to deadlock, and even after a lot of research, I can't figure out why. When I run the code in a debugger, the code appears to stall on the line
pthread_cond_wait(&(cb->buffer_empty),&(cb->mutex));
Why is the code stalling here and how can I prevent it from stalling?
回答1:
Did you say "smaller than the message", in singular? If the buffer is not big enough to store even one message, than the producer will stop halfway writing it in the queue and never get around to notifying the consumer that it has something to consume.
Brief scan through the code seems to confirm that -- if even one message can't be written, you block in the writing loop and don't get to the pthread_cond_signal
call at the end of the function, so you never notify the consumer and it can't free up the buffer.
This problem is principal. The elementary unit that the consumer can start consuming has to fit in the queue. You can resolve the problem in two ways -- either make sure the buffer is large enough for the message, or make the message processable in smaller units and notify the consumer (pthread_cond_signal
) after each unit.
来源:https://stackoverflow.com/questions/10782438/producer-consumer-seems-to-be-in-deadlock-when-buffer-is-smaller-than-input-from