2013-02-23 2 views
0

У меня есть следующий код:чтение файл построчно с помощью Pthreads ... неожиданно завершает работу

/*//not important 
    FILE * INFILE; 
    list_file = optarg; 
    if((INFILE = fopen(list_file, "a+")) == NULL) { 
     fprintf(stderr, "Can't open input file\n"); 
     exit(0); 
    } 
    */ 

    pthread_mutex_t input_queue; 
    pthread_mutex_init(&input_queue, NULL); 

    for(i = 0 ; i < number_thread; i++) 
    { 
     if(pthread_create(&thread_id[i], NULL, &work, NULL) != 0) 
     { 
      i--; 
      fprintf(stderr, RED "\nError in creating thread\n" NONE); 
     } 
    } 
    for(i = 0 ; i < number_thread; i++) 
     if(pthread_join(thread_id[i], NULL) != 0) 
     { 
      fprintf(stderr, RED "\nError in joining thread\n" NONE); 
     } 




    void * work(void * data) 
    { 
     unsigned long line; 
     char buf[512]; 
     while (!feof(INFILE)) 
     { 
      pthread_mutex_lock(&input_queue); 
      fgets((char *)&buf, sizeof(buf), INFILE); 
      if (buf[strlen (buf) - 1] == '\n') 
       buf[strlen (buf) - 1] = '\0'; 
      line = (unsigned long)buf; 
      pthread_mutex_unlock(&input_queue); 
      do_work(line); 
     } 
     fclose(INFILE); 
     return NULL; 
    } 

он читает строку из файла, но через некоторое время он неожиданно завершает работу, не сообщение об ошибке. Наверное, я что-то испортил.

Как я могу прочитать файл строки за строкой с помощью pthreads, но при этом сохранить как можно больше код без изменений (я имею в виду не испортить всю программу)?

+0

'feof', вероятно, не работает так, как вы думаете. –

+0

Зачем вам это делать? это не имеет смысла. –

+0

, конечно, вот почему я спросил здесь, где так много экспертов. Я новичок – ShaMora

ответ

2

Вы закрываете INFILE в первом потоке, который встречает EOF. Впоследствии другие потоки будут звонить feof() - и, возможно, fclose() - в закрытом файле, который повредит кучу и почти наверняка приведет к сбою. Кроме того, ваш код перекоса строки может поднять ваш буфер в EOF, см. Примечание ниже.

Чтобы устранить эту проблему, защитите feof() и fclose() с тем же мьютексом и установите INFILE в NULL. Когда мьютекс приобретается, проверьте INFILE быть NULL и немедленно вернуться, если так:

for (;;) { 
    pthread_mutex_lock(&input_queue); 
    if (!INFILE) { 
    pthread_mutex_unlock(&input_queue); 
    break; 
    } 
    if (feof(INFILE)) { 
    INFILE = NULL; 
    pthread_mutex_unlock(&input_queue); 
    break; 
    } 

    fgets(buf, sizeof(buf), INFILE); 
    pthread_mutex_unlock(&input_queue); 

    // ...strip newline, do_work... 
} 

Несколько замечаний:

  • ваш код пишет buf[strlen(buf) - 1] без проверки ли strlen(buf) равен нулю. buf будет пустым в EOF, так что это не теоретическая проблема, это произойдет ровно один раз в каждом исполнении.

  • line имеет тип unsigned long, но вы назначаете ему значение указателя. Это не удастся на платформах, где long не содержит указателя, такого как Win64. Объявите line и аргумент do_work как char * (или void *, если он должен принимать другие типы указателей).

  • избегать вызова мьютекса «очередь»; в многопоточной очереди программирования относится к producer-consumer aware FIFO.

  • Вам не нужно защищать отдельные функции stdio, такие как fgets с мьютексами. Они безопасны для МТ, как утверждается POSIX. (Тем не менее, в моем модифицированном коде, fgets() действительно должен быть мьютекс защищен, потому что INFILE может стать недействительным в то время как мьютекс не проводится.)

  • (char *) &buf не имеет смысла. Поскольку buf - это массив char, он уже распадается на указатель на его первый член, поэтому вы можете просто отправить buf в fgets. Если вы настаиваете на использовании адреса оператора, правильное выражение будет &buf[0].

  • как указано в Carl Norum, feof(), вероятно, не то, что вы хотите, так как оно обнаруживает только состояние EOF, которое уже встречается в fgets(). Правильный способ проверки EOF заключается в проверке того, возвращает ли fgets() пустую строку - перед снятием новой строки.

+0

Благодарю вас. Должен ли я добавить ваш код к недействительной работе или внутри основного? – ShaMora

+0

@ShaMora Этот цикл предназначен для замены 'while (! Feof (INFILE)) {...} 'loop. – user4815162342

+0

Я вижу, спасибо! Я проверю его прямо сейчас и опубликую результат. – ShaMora

0

если INFILE является глобальной переменной, то вы закрыли refrence в функции потока, и если вы создали несколько потоков, то flcose (INFILE) в других потоках т.е. fclose (NULL), как ожидается, к краху. Не можете догадаться, что вы пытаетесь сделать с несколькими потоками, но лучше закрыть его в конце, когда вы уверены, что INFILE больше не будет доступа ни к какому другому потоку. Я думаю, вы должны закрыть INFIL refrence в основном после того, как все потоки присоединились к основным и сделали свою обработку.

#include<stdio.h> 
#include<pthread.h> 
#include<string.h> 
#include<stdlib.h> 
#define number_thread 10 

FILE * INFILE; 
char *list_file = "test_thread"; 
pthread_mutex_t input_queue; 

void do_work(unsigned long buf) 
{ 
    printf("working on %u\n",buf); 
} 

void * work(void * data) 
{ 
    unsigned long line; 
    char buf[512]; 
    printf("IAM NEW THREAD\n"); 

    while (!feof(INFILE)) 
     { 
     pthread_mutex_lock(&input_queue); 
     fgets((char *)&buf, sizeof(buf), INFILE); 
     if (buf[strlen (buf) - 1] == '\n') 
      buf[strlen (buf) - 1] = '\0'; 
     line = (unsigned long)buf; 
     pthread_mutex_unlock(&input_queue); 
     do_work(line); 
     } 

    return NULL; 
} 

int main() 
{ 
    printf("IAM MAIN THREAD\n") 
    pthread_mutex_init(&input_queue, NULL); 
    if((INFILE = fopen(list_file, "a+")) == NULL) { 
     fprintf(stderr, "Can't open input file\n"); 
     exit(0); 
    } 
    pthread_t thread_id[10]; 

    int i=0; 
    for(i = 0 ; i < number_thread; i++) 
     { 
     if(pthread_create(&thread_id[i], NULL, &work, NULL) != 0) 
      { 
      i--; 
      fprintf(stderr, "\nError in creating thread\n"); 
      } 
     } 

    for(i = 0 ; i < number_thread; i++) 
     if(pthread_join(thread_id[i], NULL) != 0) 
      { 
      fprintf(stderr, "\nError in joining thread\n"); 
      } 

    fclose(INFILE); 
} 
+0

Да, я удалил fclose (INFILE); из-за недействительной работы и закрывается в основном, но все равно неожиданно выходит – ShaMora

+0

. Я поместил код в необработанном виде, поскольку я не могу догадаться о вашем намерении создать несколько потоков. Но теперь код не сбой, раньше была перезапись стека. . :-) –

+0

У меня есть свой код, с грубым редактированием идеи, он не сможет неожиданно выйти –

Смежные вопросы