Добрый вечер! Ищу помощи, я совсем недавно начал писать под Linux и в частности под Android, поэтому многим мой вопрос может показаться глупым. Я хочу запустить программку, которая складывает два числа, из другой программы для этого написал небольшую функцию. Вызывается как то так Код (Text): RunFile("SimpleApp"); Код (Text): int RunFile(char const* FileName) { string LaunchName(".//"); LaunchName.append(FileName); char *arg[] = {const_cast<char*>(FileName), NULL}; int res = 0; int pid = 0; switch(pid=fork()) { case -1: printf("fork error %d\n", pid); /* произошла ошибка */ res = -1; /*выход из родительского процесса*/ break; case 0: printf("execv start\n"); /* произошла ошибка */ execv(LaunchName.c_str(), arg);[spoiler][/spoiler] printf("execv end\n"); res = 0; break; default: exit(0); break; } return res; } В общем получилось что-то странное, пока работает основное приложение, второе живет и корректно обрабатывает свой ввод, но если родитель умер, то умер сразу и ребенок, а как сделать так, что бы ребенок остался жив?
Можно использовать двойной форк. Это когда родитель запускает чайлда, а чайлд уже запускает нужный нам процесс. Тогда при килле родителя, прибивается он сам и его чайлд, а grandchild'а усыновляет init. Сам недавно сталкаивался с подобной проблемой, но писал на Bash. Выглядит так: Код (Bash): xPID=$(xautolock $sleeper >/dev/null & echo $!) Здесь я запускаю демона xautolock через двойной форк и выкидываю вверх его pid, чтобы потом обрабатывать. При килле основного процесса, xautolock остается жив и переходит к init'у. Как-то так. Если есть вопросы, то спршивайте UPD: а лучше загуглите "double fork", когда искал, то видел реализации на Сях.
Огромное спасибо! Не представляю, как я должен был сам до такого дойти! в данный момент получается следующее: Код (Text): int RunFile(char const* FileName) { //http://thinkiii.blogspot.ru/2009/12/double-fork-to-avoid-zombie-process.html string LaunchName(".//"); LaunchName.append(FileName); char *arg[] = {const_cast<char*>(FileName), NULL}; int res = 0; pid_t pid_1 = 0; pid_t pid_2 = 0; int status=0; switch(pid_1=fork()) { case -1: printf("fork error %d\n", pid_1); /* произошла ошибка */ res = -1; /*выход из родительского процесса*/ break; case 0: printf("fork 2\n"); pid_2=fork(); if(pid_2) exit(0); else if(!pid_2) { printf("execv start\n"); /* произошла ошибка */ execv(LaunchName.c_str(), arg); printf("execv end\n"); } else { res = -1; printf("fork 2 error %d\n", pid_2); } break; default: waitpid(pid_1, &status, 0); break; } return res; } Запускается такая программа Код (Text): #include <stdio.h> int main() { int a,b; printf("Enter two numbers a and b: "); scanf("%d %d", &a, &b); printf("a+b = %d\n", a+b); return 0; } Результат в терминале Код (Text): root@hammerhead:/data/local # ./loader fork 2 execv start root@hammerhead:/data/local # Enter two numbers a and b: a+b = -1225222659 3 4 sush: 3: not found не очень понятно почему так, и почему он ожидает ввода после вывода a+b?
Попробовал сегодня сделать следующее, заменить код запускаемого приложения на Код (Text): int main() { for(int i = 0; i<20;i++) { printf("SimpleApp working\n"); sleep(5); } return 0; } Код выводит, прога работает, но почему та версия, не ждет ввода мне не понятно.
Хм, переписал Ваш пример на чистых сях, он запускает его ,но не дает ничего ввести. Далее я заподозрил проблему в stdin, и решил даблфоркнуть оконное приложение, которое писалось на yad - все отлично работает. Проблема 100% в stdin. Идем дальше. Повторный просмотр вашего кода выявил проблему: завершение родителя приводит к закрытию stdin, а у Вас в коде я не вижу wait()... Накладываем патч: Код (C): .... case 0: printf("fork 2\n"); pid_2=fork(); if(pid_2){ wait(NULL); /* ждем грэндчайлд*/ exit(0); } else if(!pid_2) .... Проблема скорее в scanf()...
Вообще, странно. При убивании родителя дочерний процесс должен сменить родителя на init. Вот пример: child.cpp: Код (C++): #include <stdio.h> #include <unistd.h> int main() { while (1) { printf("Hello, world!\n"); sleep(1); } return 0; } root.cpp: Код (C++): #include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid = fork(); if (pid == 0) { char *const argv[] = { NULL }; execv("./child", argv); } else if (pid > 0) { int status = 0; waitpid(pid, &status, 0); } return 0; } Компиляем так: Код (Bash): g++ root.cpp -o root g++ child.cpp -o child Запускаем: Код (Bash): ./root Hello, world! Hello, world! Hello, world! Hello, world! ... Смотрим в процессы: Код (Bash): ps afxu ... sadko 24745 0.0 0.0 18668 2380 pts/19 Ss фев13 0:00 \_ /bin/bash sadko 27593 0.1 0.1 46500 9460 pts/19 S+ 12:15 0:01 | \_ /usr/bin/mc -P /tmp/mc-sadko/mc.pwd.24745 sadko 27595 0.0 0.0 19012 6640 pts/33 Ss 12:15 0:00 | \_ bash -rcfile .bashrc sadko 27995 0.0 0.0 12404 1404 pts/33 S+ 12:31 0:00 | \_ ./root sadko 27996 0.0 0.0 12408 1424 pts/33 S+ 12:31 0:00 | \_ [child] ... Видим, что child дочерний от root Убиваем root: Код (Bash): kill -9 27995 Смотрим, что стало с child: Код (Bash): ps afxu | grep child sadko 28009 0.0 0.0 10576 1460 pts/20 S+ 12:33 0:00 | \_ grep --color=auto child sadko 27996 0.0 0.0 12408 1424 pts/33 S 12:31 0:00 [child] Видим, что child жив-здоров, только теперь наследуется от init. Смотрим по-прежнему в консоль, где запущен child: Код (Bash): Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! Hello, world! ... Теперь child можно прибить только по kill: Код (Bash): kill -9 27996
Это я уже тупанул. В Bash юзал либу, а она подчищает всех чайлдов автоматически. Вообще это хороший тон: зачищать все дочерние процессы. Поэтому пришлось извращаться с double fork'ами. Проблема в wait() и stdin в общем-то...
psh3nka, SadKo, большое спасибо за ваши ответы. То есть в текущем варианте, у меня все будет работать, за исключением ввода? меня в целом это устроит... Что бы жил ввод надо дожидаться внука. А есть ли другой способ сделать ввод? как то подвязаться программно к stdin? это вопрос более теоретический.
drem1lin, проблема в том, что когда ваш родительский процесс убивается, stdin автоматом закрывается. И это, в принципе, логично, так как вы теряете связь с терминалом, из которого были запущены. Вернее, происходит так: интерпретатор ловит сигнал SIGCHLD (завершение дочернего процесса) и закрывает pipe, который был у него ассоциирован с stdin дочернего процесса. Разумеется, после одностроннего закрытия пайпа вы ничего не сможете оттуда прочитать. child.cpp: Код (C++): #include <stdio.h> #include <unistd.h> #include <errno.h> int main() { char str[256]; while (1) { printf("Please enter something: "); fflush(stdout); if (fgets(str, sizeof(str), stdin) == NULL) break; printf("You've entered: %s", str); } printf("STDIN has been closed, error code=%d\n", int(errno)); return 0; } root.cpp: Код (C++): #include <stdio.h> #include <unistd.h> #include <sys/wait.h> int main() { pid_t pid = fork(); if (pid == 0) { char *const argv[] = { NULL }; execv("./child", argv); } else if (pid > 0) { fclose(stdin); int status = 0; waitpid(pid, &status, 0); } return 0; } В данном случае, если вы прибьёте родителя, дочерний процесс отвалится по EIO (errno == 5).