2016-10-22 5 views
1

Я пытаюсь изучить многопоточное и многопроцессорное программирование. Я очень новичок в многопоточных/обработанных программах и среде Ubuntu. Я работал над кодом ниже в течение 10 часов и исправил все ошибки и предупреждения. Я начал кодировать это с помощью xCode, и он работает отлично и делает именно то, что я хочу, чтобы он делал без каких-либо предупреждений или ошибок в этой среде. Но когда пытаюсь скомпилировать и запускать на Ubuntu, я получаю ошибку сегментации (ядро сбрасывается). Я не мог понять, какая часть кода приводит к этой ошибке. Любые идеи о том, какая часть может вызвать ошибку? или почему я получаю это? Насколько я помню, у Linux нет ядра? Огромное спасибо заранее!Ошибка сегментации (сбрасывание ядра) на виртуальном Ubuntu64bit

#include <stdio.h> 
#include <unistd.h> 
#include <pthread.h> 
#include <err.h> 
#include <sys/types.h> 
#include <dirent.h> 
#include <regex.h> 
#include <string.h> 
#include <stdlib.h> 

int pid, i, rc, pid1, counter; 
char* iterator[500]; 
char* file[500]; 
enum { 

    WALK_OK = 0, 
    WALK_BADPATTERN, 
    WALK_BADOPEN, 
}; 

int walker(const char *dir, const char *pattern) 
{ 
    struct dirent *entry; 
    regex_t reg; 
    DIR *d; 
    counter=0; 
    if (regcomp(&reg, pattern, REG_EXTENDED | REG_NOSUB)) 
     return WALK_BADPATTERN; 
    if (!(d = opendir(dir))) 
     return WALK_BADOPEN; 
    while ((entry = (readdir(d)))){ 
     if (!regexec(&reg, entry->d_name, 0, NULL, 0)){ 
      puts(entry->d_name); 
      file[counter]=entry->d_name; 
      counter=counter+1;} 
    } 
    closedir(d); 
    regfree(&reg); 
    return counter; 
} 


void* project_statistics(int i){ 

    FILE* f; 
// size_t len; 
    char* line; 
    int read[3]; 
    int arr[1000]; 
    int p, m, fnl; 

    int counter2=0; 
    f=fopen(iterator[i], "r"); 

    if (f==NULL) { 
     err(1, "%s", iterator[i]); 

    } 
    while((line=fgets((char*)read,sizeof(read),f))){ 

     sscanf(line, "%d %d %d",&p, &m, &fnl); 
     arr[counter2]= p; 
     counter2++; 
    } 

    int *firstHalf = malloc((counter2) * sizeof(int)); 
    memcpy(firstHalf, arr, (counter2) * sizeof(int)); 

    //sort array; 
    int k, l, tmp; 

    for (k = 1; k < counter2; k++) { 

     l = k; 

     while (l > 0 && firstHalf[l - 1] > firstHalf[l]) { 

      tmp = firstHalf[l]; 
      firstHalf[l] = firstHalf[l- 1]; 
      firstHalf[l- 1] = tmp; 
      l--; 

     } 

    } 

    printf("course %d project median: %d, project min: %d, project max: %d\n", i+1, firstHalf[counter2/2], firstHalf[0],firstHalf[counter2-1]); 

    if(!feof(f)){ 
     err(1, "getIn"); 
    } 
    pthread_exit(NULL); 

} 

void* midterm_statistics(int i){ 

    FILE* f; 
    int read[3]; 
    char* line; 
    int arr2[1000]; 

    int p, m, fnl; 

    int counter2=0; 

    f=fopen(iterator[i], "r"); 

    if (f==NULL) { 
     err(1, "%s", iterator[i]); 

    } 

    while((line=fgets((char*)read,sizeof(read),f))){ 

     sscanf(line, "%d %d %d",&p, &m, &fnl); 
     arr2[counter2]=m; 
     counter2++; 
    } 
    int *firstHalf = malloc((counter2) * sizeof(int)); 
    memcpy(firstHalf, arr2, (counter2) * sizeof(int)); 

    //sort array; 
    int k, l, tmp; 

    for (k = 1; k < counter2; k++) { 

     l = k; 

     while (l > 0 && firstHalf[l - 1] > firstHalf[l]) { 

      tmp = firstHalf[l]; 
      firstHalf[l] = firstHalf[l- 1]; 
      firstHalf[l- 1] = tmp; 
      l--; 

     } 

    } 

    printf("course %d project median: %d, project min: %d, project max: %d\n", i+1, firstHalf[counter2/2], firstHalf[0],firstHalf[counter2-1]); 
    if(!feof(f)){ 
     err(1, "getIn"); 
    } 
    pthread_exit(NULL); 

} 

void* final_statistics(int i){ 

    FILE* f; 
    char* line; 
    int arr3[1000]; 
    int read[3]; 
    int p, m, fnl; 

    int counter2=0; 

    f=fopen(iterator[i], "r"); 

    if (f==NULL) { 
     err(1, "%s", iterator[i]); 

    } 

    while((line=fgets((char*)read,sizeof(read),f))){ 

     sscanf(line, "%d %d %d",&p, &m, &fnl); 
     arr3[counter2]=fnl; 
     counter2++; 
    } 

    int *firstHalf = malloc((counter2) * sizeof(int)); 
    memcpy(firstHalf, arr3, (counter2) * sizeof(int)); 

    //sort array; 
    int k, l, tmp; 

    for (k = 1; k < counter2; k++) { 

     l = k; 

     while (l > 0 && firstHalf[l - 1] > firstHalf[l]) { 

      tmp = firstHalf[l]; 
      firstHalf[l] = firstHalf[l- 1]; 
      firstHalf[l- 1] = tmp; 
      l--; 

     } 

    } 

    printf("course %d project median: %d, project min: %d, project max: %d\n", i+1, firstHalf[counter2/2], firstHalf[0],firstHalf[counter2-1]); 

    if(!feof(f)){ 
     err(1, "getIn"); 
    } 
    pthread_exit(NULL); 

} 



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

    char k[500]; 

    int counter1=walker("/home/ey/Desktop/sampleFolder/", ".\\.txt"); 
    for (i=0; i<counter1; i++) { 
     strcpy(k, "/home/ey/Desktop/sampleFolder/"); 
     strcat(k, file[i]); 
     iterator[i]=strdup(k); 
     printf("%s",iterator[i]); 
    } 

    printf("\nMaster is starting\n"); 

    pthread_t tid1[counter1], tid2[counter1], tid3[counter1]; 
    pthread_attr_t attr; 
    pthread_attr_init(&attr); 
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); 
    printf("\nslave1 start\n"); 
    printf("\n~Project Statistics~\n"); 

    sleep(2); 
    for (i=0; i<counter1; i++) { 

     rc=pthread_create(&tid1[i], &attr, (void*)*project_statistics,(void*)(intptr_t)i); 

    } 

    sleep(2); 

    printf("\nslave1 done\n"); 


    printf("\nslave2 start\n"); 
    printf("\n~Midterm Statistics~\n"); 

    pid=fork(); 
    sleep(2); 
    if (pid==0) { 
     for (i=0; i<counter1; i++) { 

      rc=pthread_create(&tid2[i], &attr,(void*)*midterm_statistics, (void*)(intptr_t)i); 
     } 

     sleep(2); 
     printf("\nslave2 done\n"); 
     printf("\nslave3 start\n"); 
     printf("\n~Final Statistics~\n"); 
    } 
    sleep(2); 

    pid1=fork(); 
    sleep(2); 

    if ((pid1==0)&&(pid==0)) { 

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

      rc=pthread_create(&tid3[i], &attr, (void*)*final_statistics, (void*)(intptr_t)i); 
     } 

     sleep(2); 
     printf("\nslave3 done\n"); 
     printf("\nMaster is done\n"); 
    } 




    sleep(1); 
    pthread_attr_destroy(&attr); 
    pthread_exit(NULL); 

} 
+1

«Основной файл» - это копия памяти процесса и дополнительная информация. Он записывается в файл и может использоваться для отладки программы. Если вы не можете найти основной файл, отметьте 'ulimit -c'. Возможно, вам придется изменить лимит пользователя, например. 50000. (запустите команду ulimit -c 50000). Если у вас есть исполняемый файл и основной файл, запустите 'gdb exefile corefile', чтобы запустить отладчик gnu. Затем выполните команду 'backtrace' внутри gdb. Надеюсь, это будет отображаться там, где ваш код не работает. Используйте параметры gcc -O0 -ggdb для получения информации об отладке. –

+0

Я раньше не использовал отладчик gnu. Но когда я набрал ulimit -c, я получил 0, это нормально? также, когда я набрал ulimit -c 50000, ничего не появилось. – Valentino

+1

Ничего не отображается, но в следующий раз, когда ваша программа выйдет из строя, будет создан основной файл. Слово предупреждения: Gdb - не самый простой отладчик, доступный в Linux. Вы можете искать альтернативы. ddd может быть лучше. –

ответ

1

В main, ваш strcat является разломообразование.

Адрес источника: file[i]. file - глобальный массив указателей char *. Но, по-видимому, он ни разу не инициализировался.

Таким образом, вызов strcat будет иметь второй аргумент NULL, который вызывает segfault.

Это может произойти, если walker возвращает ненулевое значение, которое было бы, если каталог не существует (т. Е. Возврат WALK_BADOPEN). Это может объяснить, почему оно работает в одной системе, но не в другом (т. Е. Каталог существует на одном, а не другом).

Таким образом, walker использует код ошибки, но main использует это возвращаемое значение как счетчик. Эта логика неверна. Я считаю, что вам нужно изменить возвращаемое значение walker или у вас есть main получить счет по-другому.

Простой способ исправить это, чтобы сделать коды ошибок отрицательными и иметь main. Затем walker может правильно вернуть счет.

Таким образом, если каталог не существует, возвращаемое значение равно 2. Цикл в main будет придираться по file[0], потому что ничто в file не было установлено ни к чему.


UPDATE:

Но за это время, так как я знаю, что каталог существует, я мог бы пытаться открыть его в неправильном направлении?

Нет никакого «неправильного» способа использования opendir - либо открывается, либо не удается, что вы уже обрабатываете.

Но внутри walker вы не можете положиться на значение d_name от итерации цикла до итерации, поэтому вам нужно использовать strdup.

Изменение:

file[counter] = entry->d_name; 

В:

file[counter] = strdup(entry->d_name); 

Кроме того, вы должны ограничить проверку на максимальной для file (например,В настоящее время только 500)


UPDATE # 2:

В ваши функции резьбы, вы делаете fgets в read [не хороший выбор из read функции LibC в]. Но это было:

int read[3]; 

Таким образом, буфер линия была длиной всего 12 байт. Это может привести к тому, что fgets прочитает строку как две части частично разделенные. Это может вызвать arr массив переполнение

Я изменил это:

char buf[1000]; 

Я объединил скопированный код функций резьбы на обычный.

Учтите, что firstHalf был выделен, но не был освобожден. Таким образом, это было «утечка». Я добавил для него free.

Также обратите внимание, что не было fclose(f), что может привести к возврату fopenNULL (т. Е. Другому источнику для segfault).

Я также переработал нить соединения и fork логики и добавил waitpid. Также обратите внимание на добавление exit(0) к дочернему коду fork.

Как я пытался понять вещи, я упрощая, таким образом, следующим является справедливой переделкой, и может показаться немного «чужой» в первом [простите пожалуйста безвозмездную ыборку стиля]:

#include <stdio.h> 
#include <unistd.h> 
#include <pthread.h> 
#include <err.h> 
#include <sys/types.h> 
#include <dirent.h> 
#include <regex.h> 
#include <string.h> 
#include <stdlib.h> 
#include <sys/wait.h> 

#if 1 
#define MYDIR "/home/ey/Desktop/sampleFolder/" 
#else 
#define MYDIR "/tmp/data/" 
#endif 

#define dbgprt(_fmt...) \ 
    do { \ 
     if (opt_dbg) \ 
      printf(_fmt); \ 
    } while (0) 

int opt_dbg; 

int pid; 
int i; 
int rc; 
int pid1; 
int counter; 

char *iterator[500]; 
char *file[500]; 

enum { 
    WALK_OK = 0, 
    WALK_BADPATTERN = -1, 
    WALK_BADOPEN = -2, 
}; 

int 
walker(const char *dir,const char *pattern) 
{ 
    struct dirent *entry; 
    regex_t reg; 
    DIR *d; 

    counter = 0; 
    if (regcomp(&reg,pattern,REG_EXTENDED | REG_NOSUB)) 
     return WALK_BADPATTERN; 

    d = opendir(dir); 
    if (d == NULL) 
     return WALK_BADOPEN; 

    while (1) { 
     entry = readdir(d); 
     if (entry == NULL) 
      break; 

     if (!regexec(&reg,entry->d_name,0,NULL,0)) { 
      puts(entry->d_name); 
      file[counter] = strdup(entry->d_name); 
      counter = counter + 1; 
     } 
    } 

    closedir(d); 
    regfree(&reg); 
    return counter; 
} 

void * 
thread_common(void *arg,int column) 
{ 
    intptr_t i = (intptr_t) arg; 
    FILE *f; 

    // size_t len; 
    char *line; 
    int data[3]; 
    char buf[1000]; 
    int arr[1000]; 

    int counter2 = 0; 

    f = fopen(iterator[i],"r"); 
    if (f == NULL) { 
     err(1,"%s",iterator[i]); 
    } 

    dbgprt("DEBUG reading ...\n"); 
    while (1) { 
     line = fgets(buf,sizeof(buf),f); 
     if (line == NULL) 
      break; 

     sscanf(line,"%d %d %d",&data[0],&data[1],&data[2]); 
     arr[counter2] = data[column]; 

     counter2++; 
     dbgprt("DEBUG line %d %s\n",counter2,iterator[i]); 
     if (counter2 >= 1000) { 
      printf("overflow %s\n",iterator[i]); 
      exit(1); 
     } 
    } 

    if (!feof(f)) { 
     err(1,"getIn"); 
    } 

    fclose(f); 

    int *firstHalf = malloc((counter2) * sizeof(int)); 
    memcpy(firstHalf,arr,(counter2) * sizeof(int)); 

    // sort array; 
    int k, 
    l, 
    tmp; 

    dbgprt("DEBUG sorting ...\n"); 
    for (k = 1; k < counter2; k++) { 
     for (l = k; (l > 0) && (firstHalf[l - 1] > firstHalf[l]); l--) { 
      tmp = firstHalf[l]; 
      firstHalf[l] = firstHalf[l - 1]; 
      firstHalf[l - 1] = tmp; 
      l--; 
     } 
    } 

    printf("course %ld project median: %d, project min: %d, project max: %d\n", 
     i + 1,firstHalf[counter2/2],firstHalf[0],firstHalf[counter2 - 1]); 

    free(firstHalf); 

    return (void *) 0; 
} 

void * 
project_statistics(void *arg) 
{ 

    return thread_common(arg,0); 
} 

void * 
midterm_statistics(void *arg) 
{ 

    return thread_common(arg,1); 
} 

void * 
final_statistics(void *arg) 
{ 

    return thread_common(arg,2); 
} 

int 
main(int argc,char **argv) 
{ 
    intptr_t i; 
    char *cp; 
    char krkt[500]; 

    --argc; 
    ++argv; 

    for (; argc > 0; --argc, ++argv) { 
     cp = *argv; 
     if (*cp != '-') 
      break; 

     switch (cp[1]) { 
     case 'd': 
      opt_dbg = 1; 
      break; 

     default: 
      break; 
     } 
    } 

    int counter1 = walker(MYDIR,".\\.txt"); 
    dbgprt("main: walker returned %d\n",counter1); 
    if (counter1 <= 0) 
     exit(1); 

    for (i = 0; i < counter1; i++) { 
     strcpy(krkt,MYDIR); 
     if (file[i] == NULL) 
      exit(3); 
     strcat(krkt,file[i]); 
     iterator[i] = strdup(krkt); 
     printf("%s\n",iterator[i]); 
    } 

    printf("\nMaster is starting\n"); 

    pthread_t tid1[counter1]; 
    pthread_t tid2[counter1]; 
    pthread_t tid3[counter1]; 
    pthread_attr_t attr; 

    pthread_attr_init(&attr); 
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE); 
    printf("\nslave1 start\n"); 
    printf("\n~Project Statistics~\n"); 

    //sleep(2); 
    for (i = 0; i < counter1; i++) 
     rc = pthread_create(&tid1[i],&attr,project_statistics,(void *) i); 

    for (i = 0; i < counter1; i++) 
     rc = pthread_join(tid1[i],NULL); 
    printf("\nslave1 done\n"); 

    pid = fork(); 
    if (pid == 0) { 
     printf("\nslave2 start\n"); 
     printf("\n~Midterm Statistics~\n"); 

     for (i = 0; i < counter1; i++) 
      rc = pthread_create(&tid2[i],&attr,midterm_statistics,(void *) i); 

     for (i = 0; i < counter1; i++) 
      rc = pthread_join(tid2[i],NULL); 

     printf("\nslave2 done\n"); 
     exit(0); 
    } 

    pid1 = fork(); 
    if (pid1 == 0) { 
     printf("\nslave3 start\n"); 
     printf("\n~Final Statistics~\n"); 

     for (i = 0; i < counter1; i++) 
      rc = pthread_create(&tid3[i],&attr,final_statistics,(void *) i); 

     for (i = 0; i < counter1; i++) 
      rc = pthread_join(tid3[i],NULL); 

     printf("\nslave3 done\n"); 
     exit(0); 
    } 

    waitpid(pid,NULL,0); 
    waitpid(pid1,NULL,0); 
    printf("\nMaster is done\n"); 

    pthread_attr_destroy(&attr); 

    return 0; 
} 

UPDATE # 3:

Также начало основной не очень понятно мне, почему мы ждали «D» и сделать включение случае, почему это нужно добавить argv an d argc в код? Поскольку код зависит от argv и argc в некотором смысле, может ли мой способ компиляции вызвать проблему?

Код argc/argv просто анализирует опционные аргументы. Это довольно стандартный шаблон.

В этом случае, если вы делаете ./main -d, он устанавливает opt_d. Затем макрос dbgprt проверяет это, и если он установлен, имеет значение printf. Таким образом, все printf, связанные с выходом отладки, были изменены на dbgprt.

Выполнение не изменить исполнение программы, просто добавляет дополнительный вывод отладки. Вы можете добавить еще dbgprt, если хотите.

И вы можете добавить свои собственные параметры командной строки, добавив их в switch/case.

Этот метод для «отладки печати» довольно распространен. Я предпочитаю использовать gdb, где это возможно. Лично я пытаюсь вызвать программу, используя gdb, только когда у меня есть «серьезная» ошибка, такая как segfault. gdb Могу ли я идентифицировать линию сбоев. Затем я добавляю такие вещи, как assert, отладочные отпечатки и т. Д., Чтобы устранить проблему заранее.

Я понимаю логику, но мне не удалось запустить код. Я имею в виду, что он все еще работает с xcode.

Исправлены ошибки, применимые к версии xcode.

Но в Linux это не дает каких-либо ошибок или предупреждений, но при вводе ./main я ничего не получаю ...

Если вы работаете на Linux, используйте -d. Затем обратите внимание на вывод первого dbgprt после вызова walker.

Мое лучшее предположение, что walker возвращает отрицательное значение (т. Е. Каталог не существует - шаблон в порядке, так что это то, что осталось). Или, возвращает 0, указав, что в каталоге нет файлов или нет файлов, соответствующих шаблону.

Программа должна заканчиваться exit(1), поэтому проверьте код ошибки (например, echo $?)

Вы могли [и после того, как думать об этом, вероятно, должен] изменить это первый dbgprt обратно в printf, так он всегда печатает, даже если вы не укажете -d. Таким образом, вы не получите «молчащий» сбой, но программа скажет вам, впереди, если что-то не так.


Один из способов, чтобы помочь отладить этот является использовать gdb. Сделайте gdb ./main. Затем сделайте b walker, чтобы установить точку останова на walker, затем введите run. gdb остановит программу в первом заявлении walker.

Затем вы можете ввести s в «один шаг» программы. Вы можете продолжать повторять это. Когда у вас есть приглашение, вы можете выполнить команду gdb p для печати переменных. Это позволит вам увидеть, что делает walker.

Когда линия вызова к libc функции, такие как opendir, readdir, strdup и т.д. делает s будет пытаться один шаг этих функций. Длительный, и не очень полезный. Итак, на такой строке используйте вместо этого n. Если вы делаете s по ошибке, вы можете ввести finish.

Когда вы думаете, что достаточно набрали достаточно, вы можете ввести c, что продолжит выполнение программы на полной скорости.

gdb имеет много команд, выше всего лишь несколько. Он имеет встроенную справку, поэтому введите help в командной строке.Или, help b и т. Д. Есть много учебных пособий.

+0

Но за это время, поскольку я знаю, что каталог существует, могу ли я попытаться открыть его не так? – Valentino

+0

Спасибо! Я сделал изменение, упомянутое выше (strdup), но я все еще получаю ошибку сегментации. Поскольку вы сказали, что это может произойти, когда нет директории для открытия, я дважды проверял, если я даю правильно отформатированный путь к функции walker, и я. Я также попытался инициализировать char * file [500], и только то, что не дает ошибки, инициализируется с помощью {NULL}, который для меня не имеет никакого смысла. – Valentino

+0

Я получаю разные результаты в своей системе, но это следует ожидать. Можете ли вы изменить свой вопрос и опубликовать файл данных. Или, какой диапазон значений должен быть для значений трех классов [я могу генерировать тестовые файлы]. Здесь я активно редактирую, и синхронизация/ожидание потоков и процессов требует работы. Итак, вы можете изменить свой вопрос, чтобы объяснить общее намерение. Выполнение 'sleep' после первого pthread_create не является детерминированным. Лучше зациклиться на 'pthread_join'. Это делает все потоки slave1 завершенными, прежде чем запускать потоки slave2. Это то, что вы хотите? –

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