2012-01-04 114 views
3

我正在嘗試做一個簡單的多線程使用者/生產者,其中多個讀取器和寫入器線程從文件讀取到緩衝區,然後從緩衝區讀取到文件中。它應該是線程安全的。然而,它並不像我預期的那樣。它暫停一半,但每次都在不同的路線上? 請幫我理解我做錯了什麼?!?多線程消費者,生產者C代碼,不執行?

#include <pthread.h> 
#include <stdio.h> 
#include <stdlib.h> 
//TODO Define global data structures to be used 
#define BUF_SIZE 5 
FILE *fr; 
FILE *to;   /* declare the file pointer */ 

struct _data { 
    pthread_mutex_t mutex; 
    pthread_cond_t cond_read; 
    pthread_cond_t cond_write; 
    int condition; 
    char buffer[BUF_SIZE]; 
    int datainbuffer; 
}dc1 = { 
    PTHREAD_MUTEX_INITIALIZER,PTHREAD_COND_INITIALIZER,PTHREAD_COND_INITIALIZER,0,{0},0 
}; 


void *reader_thread(void *arg) { 
    //TODO: Define set-up required 
    struct _data *d = (struct _data *)arg; 
    int killreaders = 0; 
    while(1) { 
     //TODO: Define data extraction (queue) and processing 

     pthread_mutex_lock(&d->mutex); 

     while (d->condition == 0 || d->datainbuffer<=0){ 
      pthread_cond_wait(&d->cond_read, &d->mutex); 
      if(killreaders == 1){ 
       pthread_mutex_unlock(&d->mutex); 
       pthread_cond_signal(&d->cond_read); 
       pthread_cond_signal(&d->cond_write); 
       return NULL; 
      } 

     } 
     d->condition = 0; 

     int i; 
     char res; 
     //if the buffer is not full, that means the end of file is reached and it time to kill the threads remaining. 
     if(d->datainbuffer!=BUF_SIZE) 
      killreaders = 1; 

     for (i=0; i<(sizeof d->datainbuffer); i++) { 
      res = d->buffer[i]; 
      printf("to file:%c",res); 
      fputc(res, to); 
     } 
     d->datainbuffer = 0; 


     pthread_mutex_unlock(&d->mutex); 
     pthread_cond_signal(&d->cond_write); 


    } 

    return NULL; 
} 

void *writer_thread(void *arg) { 
    //TODO: Define set-up required 
    struct _data *d = (struct _data *)arg; 
    char * pChar; 
    int killwriters = 0; 

    while(1){ 
     pthread_mutex_lock(&d->mutex); 
     while(d->condition == 1 || d->datainbuffer>0){ 
      pthread_cond_wait(&d->cond_write, &d->mutex); 
      if(killwriters==1){ 
       pthread_mutex_unlock(&d->mutex); 
       pthread_cond_signal(&d->cond_write); 
       pthread_cond_signal(&d->cond_read); 
       return NULL; 

      } 
     } 
     d->condition = 1; 
     int i; 
     char rc; 
     for (i = 0; i < BUF_SIZE; i++){ 
      if((rc = getc(fr)) == EOF){ 
       killwriters = 1; 
       pthread_mutex_unlock(&d->mutex); 
       pthread_cond_signal(&d->cond_read); 

       return NULL; 
      } 
      d->datainbuffer = i+1; 
      d->buffer[i] = rc; 
      printf("%c",rc); 
     } 

     int m = 0; 

     pthread_mutex_unlock(&d->mutex); 
     pthread_cond_signal(&d->cond_read); 


    } 


    return NULL; 
} 


#define M 10 
#define N 20 
int main(int argc, char **argv) { 
    struct _data dc=dc1; 

    fr = fopen ("from.txt", "rt"); /* open the file for reading */ 
    if (fr == NULL) 
    { 
     printf("Could not open file!"); 
     return 1; 
    } 
    to = fopen("to.txt", "wt"); 


    int i; 
    pthread_t readers[N]; 
    pthread_t writers[M]; 


    for(i = 0; i < N; i++) { 
     pthread_create(&readers[i], NULL, reader_thread, (void*)&dc); 
    } 

    for(i = 0; i < M; i++) { 
     pthread_create(&writers[i], NULL, writer_thread, (void*)&dc); 
    } 
    fclose(fr); 
    fclose(to); 

    return 0; 
} 

任何建議表示讚賞!

+0

您可以請更新您所做的更改,它可以幫助我解決類似問題。 – m4n07 2012-10-25 09:00:57

回答

3

你的線程正在讀取和寫入文件,你打開&關閉主文件。但是在關閉這些文件之前,main並沒有明確地等待線程完成。

+0

你是對的,謝謝你的幫助! – user1127217 2012-01-05 00:25:09

2

除了Scott Hunter指出的問題之外,你的讀者和作者在拿着互斥體的同時也做了他們所有的「真正的工作」,從而擊敗了首先擁有多個線程的觀點。

讀者應該如下操作:

1)獲取互斥鎖。
2)阻止條件變量,直到工作可用。
3)從隊列中刪除工作,可能是信號條件變量。
4)釋放互斥鎖。
5)處理工作。
6)轉到步驟1.

作家如下應操作:

1)獲取我們需要編寫的信息。
2)獲取互斥鎖。
3)阻塞條件變量,直到隊列中有空間。
4)將信息放置在隊列中,可能是信號條件變量。
5)釋放互斥鎖。
6)轉到步驟1.

注意兩個線程在不保持互斥鎖的情況下執行「真實工作」?否則,爲什麼有多個線程,如果只有其中一個線程可以同時工作?

+0

因爲這是比賽條件所在?或者你是說,獲取互斥鎖是不必要的,b/c cond_wait可以幫你嗎? - 沒關係(我會讀「應該操作」列表爲「操作」:) – 2012-01-04 13:04:28

+1

謝謝,這真的很有幫助!我接受了你的建議,現在它表現得更好。 – user1127217 2012-01-05 00:23:53

0

我不知道我的答案是否會幫助你..但我會給你一些參考代碼給我最好的。

我寫了一個類似的程序(除了它不寫入文件,而是在stdout中顯示隊列/生產/消耗項目)。它可以在這裏找到 - https://github.com/sangeeths/pc。我已經將命令行處理和隊列邏輯分離爲一個單獨的文件。

希望這會有所幫助!

+0

我使用了代碼中的隊列實現,因爲它更容易添加和刪除項目,謝謝! – user1127217 2012-01-05 00:24:41

+0

@ user1127217我很高興你能重用我的一些代碼。如果您覺得它有用,請隨時註冊並選擇此作爲答案。也請分享您的代碼,以便我可以查看和了解與我的不同之處。謝謝! – 2012-01-05 03:15:12