2012-05-28 3 views
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; 
} 

버퍼가 단일 클라이언트의 메시지보다 클 때 주로 작동 (16, 예를 들어, 더 큰 buffer_size함으로써). 그러나 그것을 더 작게 만들면 교착 상태에 빠져있는 것처럼 보이며 많은 연구를 한 후에도 이유를 파악할 수 없습니다. 내가 디버거에서 코드를 실행하면 코드는

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

왜 코드가 여기에 실속하고 나는 그것이 실속에서 어떻게 방지 할 수 있습니다 라인에 실속 나타 납니까?

답변

1

"메시지보다 작음"이라고 했습니까? 버퍼가 하나의 메시지 만 저장할 정도로 크지 않은 경우 생산자가 큐에 글쓰기를 중간에 멈추고 소비 할 항목이 있음을 소비자에게 알려주지 않습니다.

코드를 간략히 살펴보면 하나의 메시지 만 쓸 수 없다면 작성 루프에서 차단되고 함수의 마지막 부분에서 pthread_cond_signal 호출이 발생하지 않음을 확인할 수 있습니다. 소비자에게 알리고 버퍼를 비울 수 없습니다.

이 문제는 주된 문제입니다. 소비자가 소비하기 시작할 수있는 기본 단위는 대기열에 들어야합니다. 두 가지 방법으로 문제를 해결할 수 있습니다. 버퍼가 메시지에 대해 충분히 큰지 확인하거나 메시지를 더 작은 단위로 처리 가능하게 만들고 각 단위 후에 소비자에게 알립니다 (pthread_cond_signal).

+0

나는 당신의 대답 덕분에 그 이유를 발견했을 것이다. pthread_cond_signal (& (cb-> buffer_full)); 잘못된 장소에있다. 버퍼가 가득 차면 cond_signal에 값을 제거하기 시작해야한다는 신호를 보내야합니다. 지금 작동하는지 확인하십시오 ... – Thomas

+0

그것은 내가 그것을 해결했다고 생각합니다 (나는 잘못된 장소에서 소비자에게 신호를 보냈습니다. 이제 버퍼가 가득 찼을 때 신호를 보냅니다) 이제 둘 이상의 클라이언트 나 프로듀서를 사용할 때 여전히 문제가 있습니다. 버퍼가 비운 후에도 입력을 시작하기를 원합니다. 나는 계속해서 메시지를 전송하지 않은 생산자를 원합니다 ... – Thomas

+0

@ThomasVerbeke : 그들은 모두 생산하려고합니다. 그렇다니까. 유일한 제정신의 해결책은 소비자가 이해할 수있는 메시지를 작성하기 전까지는 결코 자물쇠를 놓아 두지 않는 것입니다. 불완전한 메시지는 여러 명의 독자 또는 여러 명의 작성자가 대기열에 나타나서는 안되는 메시지입니다. 다른 작성자 또는 다음 부분의 다른 독자가 읽지 못하도록 보장 할 수 없기 때문입니다. –