0

次のコードがあります。

    /*//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 を使用してファイルを 1 行ずつ読み取るにはどうすればよいでしょうか (プログラム全体を台無しにしないことを意味します)。

4

2 に答える 2

2

INFILEEOF に遭遇した最初のスレッドを閉じています。その後、他のスレッドが閉じたファイルに対して呼び出しfeof()を行い、場合によってfclose()は、ヒープが破損し、ほぼ確実にクラッシュが発生します。また、改行チョッピング コードは、EOF でバッファーをアンダーランする可能性があります。以下のコメントを参照してください。

この問題を解決するには、 を同じミューテックスで保護し、INFILE を NULL に設定しますfeof()fclose()ミューテックスが取得されたら、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]かどうかをチェックせずに書き込みます。は EOF で空になるため、これは理論的な問題ではなく、実行ごとに 1 回だけ発生します。strlen(buf)buf

  • lineはタイプunsigned longですが、ポインター値を割り当てています。longこれは、Win64 などのポインターを含まないプラットフォームでは失敗します。代わりにasの宣言lineと引数(または、他のポインター型を受け入れる必要がある場合) を使用してください。do_workchar *void *

  • ミューテックスを「キュー」と呼ばないようにしてください。マルチスレッド プログラミングでは、 queue はプロデューサー/コンシューマー対応の FIFOを指します。

  • fgetsミューテックスのように、個々の stdio 関数を保護する必要はありません。POSIX で義務付けられているように、これらは MT セーフです。(ただし、変更したコードでは、ミューテックスが保持されていないときに無効になる可能fgets()性があるため、ミューテックスで保護する必要があります。)INFILE

  • (char *) &buf意味がありません。bufは配列であるためchar、既に最初のメンバーへのポインターに減衰しているため、単純に に送信できbufますfgets。address-of 演算子の使用を主張する場合、正しい式は&buf[0]です。

  • Carl Norumfeof()が示唆したように、fgets(). EOF を確認する正しい方法は、 newline を削除する前にfgets()、 が空の文字列を返すかどうかをテストすることです。

于 2013-02-23T16:07:48.427 に答える
1

INFILE がグローバル変数の場合、thread の関数で参照を閉じたことになります。また、複数のスレッドを作成した場合は、他のスレッドで flcose(INFILE)、つまり fclose(NULL) がクラッシュすることが予想されます。複数のスレッドで何をしようとしているのかは推測できませんが、INFILE が他のスレッドからアクセスされなくなったことが確実な場合は、最後に閉じることをお勧めします。メインに参加し、処理を行いました。

#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);
}
于 2013-02-23T16:39:19.580 に答える