#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.