2016-03-25 14 views
1

ディレクトリ内のすべてのファイルを取得し、個々のチェックサムを見つけて、マルチスレッドを使用して合計チェックサムを見つけるプログラムを作成しました。セグメンテーションフォールトマルチスレッドとファイルオープン

セグメント違反が発生しているので、gdbを実行して、open()が60行目にあることを確認しました。 SOや他のフォーラムでseg faultを調べた後、open()をintではなくFILE *ハンドルでfopen()に変更するなど、いくつかのアプローチを実装しようとしました。その変化は間違っていた。

数時間のデバッグと検索の後、私は無知ですし、どんな洞察にも大いに感謝します。

There are 24 files: 
.windows 
.xscreensaver 
.alias 
.cshrc 
Segmentation fault 

(gdb) run 
Starting program: /home/nolooking/a.out 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib64/libthread_db.so.1". 
There are 24 files: 
.windows 
[New Thread 0x7ffff781e700 (LWP 15957)] 
.xscreensaver 
[New Thread 0x7ffff701d700 (LWP 15958)] 

Program received signal SIGSEGV, Segmentation fault. 
[Switching to Thread 0x7ffff781e700 (LWP 15957)] 
0x0000000000400d53 in get_checksum (a=0x60b610) at checksum.c:60 
60    handle = open(filenames[b], O_RDONLY); 
(gdb) backtrace 
#0 0x0000000000400d53 in get_checksum (a=0x60b610) at checksum.c:60 
#1 0x00007ffff7bc6374 in start_thread() from /lib64/libpthread.so.0 
#2 0x00007ffff7907c3d in clone() from /lib64/libc.so.6 
(gdb) quit 
A debugging session is active. 

UPDATE: handle=fopen((char*)a, "r");: は私が使用することを示唆したコメントの中で一人のユーザのアドバイスを取っ

#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 
#include <stdarg.h> 
#include <fcntl.h> 
#include <time.h> 
#include <sys/types.h> 
#include <dirent.h> 
#include <pthread.h> ///Compile with -pthread or -lpthread 
#include <sys/stat.h> 

#define BUFFER_SIZE (1<<16) 

void cleanup(); 
void get_filenames(); 
void* get_checksum(); 

char **filenames; 
int file_cnt; 
DIR *dir; 

//int handle; 
FILE *handle; 
unsigned int checksum; 
unsigned char* ptr; 
int length; 
int count; 
unsigned char* buffer; 
int* sum; 
unsigned int total = 0; 

int main(int argc, char *argv[]){ 

     int i; 
     pthread_t* file; 

     atexit(cleanup); 
     get_filenames(); 

     printf("There are %d files:\n", file_cnt); 

     file = calloc(sizeof(pthread_t), file_cnt); 
     sum = calloc(sizeof(int), file_cnt); 
     for(i=0; i<file_cnt; i++){ 

       printf("%s\n", filenames[i]); 

       pthread_create(&(file[i]), NULL, get_checksum, (void*)&filenames[i]); 
     } 
       for(i=0; i<file_cnt; i++){ 
         total += sum[i]; 
       } 
       printf("total is: %u\n", total); 
     return EXIT_SUCCESS; 
} 

void* get_checksum(void* a){ 

     int b = *((int *)a); 

     //handle = open(filenames[b], O_RDONLY); //SEG FAULT HERE 
       handle = fopen(filenames[b], "r"); //SEG FAULT HERE 
       if(handle == NULL){ 
         printf("Can't open file: %s\n", filenames[b]); 
         exit(1); 
     } 

       buffer = malloc(BUFFER_SIZE); 
     if(buffer == NULL){ 
         printf("Can't get enough memory\n"); 
         exit(1); 
       } 

       checksum = 0; 

       do{ 
         //length = read(handle, buffer, BUFFER_SIZE); 
         length = read(handle, buffer, (sizeof(char))); 

         if(length == -1){ 
           printf("Error reading file: %s\n", filenames[b]); 
             //return NULL; 
             exit(1); 
     } 

         ptr = buffer; 
         count = length; 
         while(count--){ 
           checksum = checksum + (unsigned int)(*ptr++); 
           sum[b] = checksum; 
           } 
     } while(length); 
       printf("Checksum= %d\nTimes at: %d\n", checksum, (int)clock()); 
} 


void cleanup() { 

     if(filenames && file_cnt > 0) { 
       while(file_cnt-- > 0) { 
         if(filenames[file_cnt]) { 
           free(filenames[file_cnt]); 
         } 
       } 
       free(filenames); 
     } 

     if(dir) { 
       closedir(dir); 
     } 

     return; 
} 


void get_filenames() { 

     struct dirent *dir_entry; 

     if((dir = opendir(".")) == NULL) { 
       fprintf(stderr, "Couldn't open the directory entry for reading\n"); 
       exit(1); 
     } 

     errno = 0; 
     file_cnt = 0; 
     while((dir_entry = readdir(dir)) != NULL) { 
       char **new_filenames = filenames; 
       static int realative_dirs = 0; 

       if(realative_dirs < 2 && 
        (strcmp(".", dir_entry->d_name) == 0 || strcmp("..", dir_entry->d_name) == 0) 
       ) { 
         realative_dirs++; 
         continue; 
       } 

       new_filenames = (char **)realloc(filenames, sizeof(char **) * (file_cnt + 1)); 
       if(new_filenames == NULL) { 
         free(filenames[file_cnt]); 
         fprintf(stderr, "Could not allocate reference for filename[%d]\n", file_cnt); 
         exit(1); 
       } 

       filenames = new_filenames; 
       filenames[file_cnt] = (char *)calloc(strlen(dir_entry->d_name) + 1, sizeof(char)); 
       if(filenames[file_cnt] == NULL) { 
         fprintf(stderr, "Could not allocate memory for filename[%d]'s string: \"%s\"\n", 
           file_cnt, dir_entry->d_name); 
         exit(1); 
       } 

       strcpy(filenames[file_cnt], dir_entry->d_name); 
       file_cnt++; 
     } 

     if(errno != 0) { 
       fprintf(stderr, "An error occured getting the filenam list\n"); 
       exit(1); 
     } 

     return; 
} 

以下は出力とGDBデバッグです。 if文if(handle==NULL)がコメントアウトされると、ファイル名を正常に出力できます。私は文の場合、私は次の出力受けることを含める場合:

There are 24 files: 
.windows 
.xscreensaver 
.alias 
.cshrc 
Can't open file: p▒` 



#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 
#include <stdarg.h> 
#include <fcntl.h> 
#include <time.h> 
#include <sys/types.h> 
#include <dirent.h> 
#include <pthread.h> 
#include <sys/stat.h> 

#define BUFFER_SIZE (1<<16) 

void cleanup(); 
void get_filenames(); 
void* get_checksum(); 

char **filenames; 
int file_cnt; 
DIR *dir; 

//int handle; 
FILE *handle; 
unsigned int checksum; 
unsigned char* ptr; 
int length; 
int count; 
unsigned char* buffer; 
int* sum; 
unsigned int total = 0; 

int main(int argc, char *argv[]){ 

     int i; 
     pthread_t* file; 

     atexit(cleanup); 
     get_filenames(); 

     printf("There are %d files:\n", file_cnt); 

     file = calloc(sizeof(pthread_t), file_cnt); 
     sum = calloc(sizeof(int), file_cnt); 
     for(i=0; i<file_cnt; i++){ 

       printf("%s\n", filenames[i]); 

       pthread_create(&(file[i]), NULL, get_checksum, (void*)&filenames[i]); 
     } 
       for(i=0; i<file_cnt; i++){ 
         total += sum[i]; 
       } 
       printf("total is: %u\n", total); 
     return EXIT_SUCCESS; 
} 

void* get_checksum(void* a){ 

     int b = *((int *)a); 

       handle = fopen(((char*)a), "r"); 
       if(handle == NULL){ 
         printf("Can't open file: %s\n", ((char*)a)); 
         exit(1); 
     } 

       buffer = malloc(BUFFER_SIZE); 
     if(buffer == NULL){ 
         printf("Can't get enough memory\n"); 
         exit(1); 
       } 

       checksum = 0; 

       do{ 
         length = read(handle, buffer, BUFFER_SIZE); 

         if(length == -1){ 
           printf("Error reading file: %s\n", ((char*)a)); 
             //return NULL; 
             exit(1); 
     } 

         ptr = buffer; 
         count = length; 
         while(count--){ 
           checksum = checksum + (unsigned int)(*ptr++); 
           //sum[a] = checksum; 
           } 
     } while(length); 
       printf("Checksum= %d\nTimes at: %d\n", checksum, (int)clock()); 
} 


void cleanup() { 

     if(filenames && file_cnt > 0) { 
       while(file_cnt-- > 0) { 
         if(filenames[file_cnt]) { 
           free(filenames[file_cnt]); 
         } 
       } 
       free(filenames); 
     } 

     if(dir) { 
       closedir(dir); 
     } 

     return; 
} 


void get_filenames() { 

     struct dirent *dir_entry; 

     if((dir = opendir(".")) == NULL) { 
       fprintf(stderr, "Couldn't open the directory entry for reading\n"); 
       exit(1); 
     } 

     errno = 0; 
     file_cnt = 0; 
     while((dir_entry = readdir(dir)) != NULL) { 
       char **new_filenames = filenames; 
       static int realative_dirs = 0; 

       if(realative_dirs < 2 && 
        (strcmp(".", dir_entry->d_name) == 0 || strcmp("..", dir_entry->d_name) == 0) 
       ) { 
         realative_dirs++; 
         continue; 
       } 

       new_filenames = (char **)realloc(filenames, sizeof(char **) * (file_cnt + 1)); 
       if(new_filenames == NULL) { 
         free(filenames[file_cnt]); 
         fprintf(stderr, "Could not allocate reference for filename[%d]\n", file_cnt); 
         exit(1); 
       } 

       filenames = new_filenames; 
       filenames[file_cnt] = (char *)calloc(strlen(dir_entry->d_name) + 1, sizeof(char)); 
       if(filenames[file_cnt] == NULL) { 
         fprintf(stderr, "Could not allocate memory for filename[%d]'s string: \"%s\"\n", 
           file_cnt, dir_entry->d_name); 
         exit(1); 
       } 

       strcpy(filenames[file_cnt], dir_entry->d_name); 
       file_cnt++; 
     } 

     if(errno != 0) { 
       fprintf(stderr, "An error occured getting the filenam list\n"); 
       exit(1); 
     } 

     return; 
} 

を私はif文のコメントを外したら、なぜ私はその出力を受けるのですか?

+0

'(void *)&filenames [i]'は**ではありません** int b = *((int *)a);または何か不足していますか? –

+0

はい。あなたはpthread_createへの引数として間違ったことを渡しています。 get_checksumは整数を想定しており、ファイル名を渡しています。 – bruceg

+0

@AdrianoRepetti私はかなり理解していません。 check_sum()が呼び出され、(void *)とファイル名[i]のvoid * aが必要です。しかし、関数check_sum()では利用できませんので、整数インデックスを作成しました。可能であれば、あなたが意味することを説明してください。 – SamSmith

答えて

1

変更この

pthread_create(&(file[i]), NULL, get_checksum, (void*)&filenames[i]); 

pthread_create(&(file[i]), NULL, get_checksum, (void*)i); 

この

int b = *((int *)a); 

int b = (int)a; 
なるようにすべき

また、fopen()によって返されるFILE*にはread()を呼び出すことはできません。代わりにfread()を使用してください。

-2

あなたの問題は単純に&iの代わりに&filenames[i]を渡しているためです。

void* get_checksum(void* a)では、char *をintとして使用しようとしています。

コードは、より多くのようになります:

for(i=0; i<file_cnt; i++){ 

       printf("%s\n", filenames[i]); 

       pthread_create(&(file[i]), NULL, get_checksum, (void*)&i); 
     } 

void* get_checksum(void* a)で:

int b = *((int *)a); 

    handle = fopen(filenames[b], "r"); 
      if(handle == NULL){ 
        printf("Can't open file: %s\n", filenames[b]); 
        exit(1); 
    } 
+0

あなたの診断は正しいですが、解決策はありません。 – alk

1

&私はを使用しないでください。私は少し説明します。スレッドに渡す引数が間違っていますは整数ではありません。

変更スレッドこれまで作成...次のように

pthread_create(&(file[i]), NULL, get_checksum, filenames[i]); 

その文字列を印刷...

void* get_checksum(void *a){ 

    char *file_name = (char *)a; 
    printf("filename=%s\n", file_name); 

あなた」...文字列へのポインタであることを意味しています呼び出した関数へのポインタとして文字列を渡します。あなたのコードでは、これを配列のインデックスとして使用しようとしています。あなたは用心整数としてインデックスを渡したい場合は

...これは

pthread_create(&(file[i]), NULL, get_checksum, &i); 

これは、マルチスレッド..です動作しませんし、値が&によって私はループとして変更さを指摘しました走るポインタを文字列に渡し、スレッドの実行時にファイル名を変更しないでください。

+0

私のアップデートをご覧ください。私はコメントセクションに提案を実装し、すべてのファイルが適切に印刷されています。しかし、if文のコメントを外すと、すべてのファイル名が出力されるわけではありません。私は上記のアップデートでより良く説明しました。 – SamSmith

+0

@SamSmithあなたはすでにあなたに答えを与えたときに私が示唆しなかったことについてコメントしてもらえますか?私が書いたことを読んでください。つまり、pthread_createの最後の引数はget_checksumに渡されます。文字列へのポインタへのポインタを渡して、それを整数として使用しようとしています。それは単に働くことができません。 – Harry

+0

あなたの提案では: 'handle = fopen(* file_name、" r ");'引数1は、キャストのない整数からポインタを作ります。 – SamSmith

関連する問題