2012-01-04 81 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