Бесконечный цикл Fork

#c #exec #fork #infinite-loop

#c #exec #fork #бесконечный цикл

Вопрос:

Я пытаюсь создать программу мониторинга каталогов на C. Пока что она обнаруживает подкаталоги основного каталога, однако проблема возникает, когда я пытаюсь отслеживать подкаталоги подкаталогов.

 char * const  son[] = { argv[0], name, NULL };  

pid_t pid = fork();
if (pid == 0) {
    execvp(son[0], son);
}
  

Этот код должен был создать дочерний процесс, который отслеживал бы подкаталоги. name это строка с подкаталогом «Desktop/test», например.
Я пытался напечатать «name» раньше, и это нужный мне подкаталог, так что проблема не здесь.

Программа работает безупречно, пока я не добавлю это. Как только я добавляю его, он переходит в бесконечный цикл, несмотря на то, что работал ранее. Я также хочу отметить, что я не использую сигналы, поэтому проблема исходит не от них.

Это, конечно, всего лишь отрывок из его кода. Если вы считаете, что мне нужно опубликовать полный код, который намного больше, я добавлю его, хотя, честно говоря, я сомневаюсь, что проблема в нем, поскольку раньше он работал идеально.

РЕДАКТИРОВАТЬ: Лучше добавьте весь код, argv[1] — это каталог, argv[2] — сколько минут я хочу, чтобы программа запускалась, argv[3] — это пауза между каждым сканированием. Это сработает, если я удалю приведенный выше отрывок, и я знаю, что это немного сбивает с толку, но если у вас есть какие-либо вопросы, просто скажите.

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


char** direc;
int direct_pos = 0;
direc = (char**) malloc(2 * sizeof(char*));


double actual_time = 0;
double MAXTIME = atof(argv[2]);
MAXTIME = MAXTIME * 60;
double IterationTime = atof(argv[3]);
time_t start = time(0);


char dot2[100];
char dot[100];

sprintf(dot, "%s/.", argv[1]); 
sprintf(dot2, "%s/..", argv[1]); 
direct_pos  ;
direc[direct_pos - 1] = (char*) malloc(strlen(dot) * sizeof(char));
strcpy(direc[direct_pos - 1], dot);
direct_pos  ;
direc[direct_pos - 1] = (char*) malloc(strlen(dot2) * sizeof(char));
    strcpy(direc[direct_pos - 1], dot2);
if (argc != 4) {
    fprintf(stderr, "Usage: %s dir_namen", argv[0]);
    exit(1);
}
while (actual_time < MAXTIME) {
    DIR *dirp;

    if ((dirp = opendir(argv[1])) == NULL) {
        perror(argv[1]);
        exit(2);
    }

    struct stat stat_buf;
    struct dirent *direntp;
    while ((direntp = readdir(dirp)) != NULL) {
        char name[100];
        sprintf(name, "%s/%s", argv[1], direntp->d_name);   
        if (lstat(name, amp;stat_buf) == -1)  
        {

            perror("lstat ERROR");
            exit(3);
        }

        if (S_ISDIR(stat_buf.st_mode)) 
                      {

            int x;
            for (x = 0; x <= direct_pos; x  ) {

                if (x == direct_pos) {

                    char**newarray;
                    newarray = (char**) malloc((direct_pos   1)* sizeof(char*));
                    int l;
                    for (l = 0; l < direct_pos; l  ) {
                                            //printf("nxxxx%dn", sizeof(direc[l]));

                        newarray[l] = (char*) malloc((strlen(direc[l]) 1)
                                * sizeof(char));


                        strcpy(newarray[l], direc[l]);
                    }

                    direc = newarray;

                    direc[direct_pos] = (char*) malloc(sizeof(name)
                            * sizeof(char));
                    direc[direct_pos] = strcpy(direc[direct_pos], name);
                    direct_pos  ;

                    double seconds_since_start = difftime(time(0), start);
                    double new_time = (MAXTIME - seconds_since_start) / 60;
                    char time_array[10];

                                          sprintf(time_array,"%f",new_time);

                    char * const  son[] = { argv[0], name, time_array,
                            argv[3], NULL };




           printf("n%sn",son[1]);
    x = direct_pos   2;     
            pid_t pid = fork();
    if (pid == 0) {
         execvp(son[0], son)==-1);
                      break;
                             }

                } else if (strcmp(name, direc[x]) == 0) {

                    x = direct_pos   2;
                }
            }

        }



    }

    sleep(IterationTime);
    actual_time  = IterationTime;
    closedir(dirp);
}

exit(0);
}
  

Комментарии:

1. Опубликуйте больше кода. Как вы читаете аргументы в main?

2. @pajton Извините, я не хотел редактировать ваши теги. Я думаю, что начал редактировать до того, как вы отправили свою правку, но отправил свою после.

3. @yetti нет проблем, я не являюсь владельцем поста 🙂

Ответ №1:

У вас есть программа, которая разветвляется, а затем запускает новую копию самой себя. Думайте об этом как о бесконечной рекурсии. Нет необходимости запускать новый экземпляр, просто напишите свой код так, чтобы программа продолжалась по одному из двух путей в зависимости от возвращаемого идентификатора процесса.

Но это неправильное решение.

Правильное решение — вообще не форкать. Вы не получаете почти никакой выгоды от наличия тысячи процессов, которые просматривают один каталог, по сравнению с одним процессом, который просматривает тысячу каталогов. На самом деле, вы можете быть намного хуже, перенеся нагрузку на планировщик.

Комментарии:

1. Это упражнение, в котором я должен использовать fork, обойти это невозможно.

2. Согласовано и, более того, ручной опрос каталогов вообще не требуется при использовании Linux (см. inotify(7) на страницах руководства).

3. @user697110 — хорошо, вы должны использовать fork() , но вам не обязательно использовать exec() . На самом деле, это упражнение, вероятно, пытается научить вас, как писать разветвленные программы, чтобы правильно обрабатывать как родительские, так и дочерние.

4. Но тогда как мне войти в подкаталог, чтобы отслеживать, есть ли в нем что-нибудь?

5. @user697110 — первое, что приходит мне в голову, это рекурсивный метод, который содержит как readdir , так и fork the, и поддерживает список каталогов, которые уже были разветвлены. Но, честно говоря, проблема мне не очень интересна, а ваш код представляет собой беспорядок, так что то, как вы решаете проблему, зависит от вас.

Ответ №2:

Похоже, что вы всегда разветвляетесь, несмотря ни на что. Я бы поставил там галочку, чтобы убедиться, что если у вас нет подкаталогов в текущем каталоге, вы не разветвляете.

Ответ №3:

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

1) Проверьте, есть ли какие-либо подкаталоги в текущем каталоге … если таковых нет, то exit() , в противном случае прочитайте все подкаталоги в текущем каталоге.

2) Для каждого подкаталога разветвляется процесс. Если fork является дочерним (т. е. pid == 0 ), то выполните вызов execvp() .

3) Если pid != 0 , то вы находитесь в родительском процессе. Вместо того, чтобы пытаться перейти в режим ожидания в течение некоторого периода времени, вызовите wait() и продолжайте повторять вызов wait() до тех пор, пока не останется дочерних процессов.

4) Как только дочерних процессов не останется (т.е. wait() возвращает статус ошибки, такой, что errno == ECHILD ), тогда вы можете вызвать exit() родительский процесс.

Итак, если вы выполните эти 4 шага, вы не должны создавать никаких бесконечных циклов. Каждый дочерний процесс в какой-то момент завершится, как только они достигнут каталога, в котором больше нет подкаталогов, и каждый родительский процесс будет ждать своих дочерних процессов перед завершением, так что в конечном итоге у вас не будет ни одного потерянного процесса. Если вы в конечном итоге получаете бесконечный цикл, то это потому, что дочерний процесс не завершается, что затем указывает на логику, используемую для определения наличия каких-либо подкаталогов в текущем каталоге, или вы неправильно определяете, что в родительском процессе больше не осталось дочерних элементов, которых можно было бы ожидать.

Надеюсь, это поможет,

Джейсон

Комментарии:

1. Это в значительной степени то, что я сделал, только не установил ожидания, собираюсь попробовать это сейчас.

2. Однако вам не нужно вызывать sleep() … вам нужен только вызов wait() . Вы могли бы сделать что-то вроде: while(wait(NULL) != -1 || errno != ECHILD); . Это ожидало бы завершения всех созданных дочерних процессов, а затем завершило бы цикл while.