Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
190 views
in Technique[技术] by (71.8m points)

c - Producer/consumer seems to be in deadlock when buffer is smaller than input from producer

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("
Producer (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("
Consumer (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("
");
    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("
DEBUG (Main Thread) - Error while creating thread");
            #endif
        } else {
            #ifdef DEBUG
            printf("
DEBUG (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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...