0

複数のクライアントがバッファに書き込む(最終的には異なるサイズのメッセージを書き込む)循環バッファを作成しました。サーバーはそれらを読み取ります。これは、消費者/生産者の問題のコードに基づいています。

#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;
}

バッファが単一のクライアントのメッセージよりも大きい場合 (buffer_sizeたとえば 16 など大きくすることによって)、ほとんどの場合機能します。しかし、小さくすると行き詰まるようで、いろいろ調べても原因がわかりません。デバッガーでコードを実行すると、コードが停止しているように見えます。

pthread_cond_wait(&(cb->buffer_empty),&(cb->mutex));

ここでコードが停止するのはなぜですか? また、停止しないようにするにはどうすればよいですか?

4

1 に答える 1

1

単数形で「メッセージよりも小さい」と言いましたか? バッファーが 1 つのメッセージを格納するのに十分な大きさでない場合、プロデューサーはキューへの書き込みを途中で停止し、消費するものがあることをコンシューマーに通知することはありません。

コードを簡単に調べてみると、メッセージが 1 つでも書き込めない場合は、書き込みループでブロックされ、pthread_cond_signal関数の最後の呼び出しに到達しないため、消費者に通知することはなく、バッファを解放できません。

この問題は主要です。消費者が消費を開始できる基本単位は、キューに収まる必要があります。この問題は 2 つの方法で解決できます。バッファーがメッセージに対して十分な大きさであることを確認するか、メッセージを小さな単位で処理できるようにして、pthread_cond_signal各単位の後でコンシューマーに通知します ( )。

于 2012-05-28T09:51:08.863 に答える