Использование exec для выполнения системной команды в новом процессе
Я пытаюсь создать процесс, который выполняет системную команду, в то время как моя собственная программа все еще продолжается, и два процесса будут выполняться параллельно. Я работаю над linux.
Я посмотрел онлайн и, похоже, должен использовать семейство exec(). Но это не работает так, как я ожидал. Например, в следующем коде я вижу только "раньше", но не "сделан".
Мне интересно, если я что-то исхожу?
#include <unistd.h>
#include <iostream>
using namespace std;
main()
{
cout << "before" << endl;
execl("/bin/ls", "/bin/ls", "-r", "-t", "-l", (char *) 0);
cout << "done" << endl;
}
[ОБНОВЛЕНИЕ]
Спасибо за комментарии ваших парней. Теперь моя программа выглядит так. Все работает нормально, кроме как в конце, я должен нажать enter, чтобы закончить программу. Я не уверен, почему мне нужно нажать последний вход?
#include <unistd.h>
#include <iostream>
using namespace std;
main()
{
cout << "before" << endl;
int pid = fork();
cout << pid << endl;
if (pid==0) {
execl("/bin/ls", "ls", "-r", "-t", "-l", (char *) 0);
}
cout << "done" << endl;
}
Ответы
Ответ 1
Вам не нужен вызов fork
. Все exec
выполняет замену текущего образа процесса на процесс новой программы. Используйте fork
, чтобы создать копию текущего процесса. Его возвращаемое значение скажет вам, работает ли это ребенок или исходный родитель. Если это ребенок, вызовите exec
.
Как только вы внесете это изменение, появится только сообщение, что вам нужно нажать Enter для завершения программ. Фактически это происходит: родительский процесс виляет и выполняет дочерний процесс. Оба процесса выполняются, и оба процесса одновременно печатаются на stdout. Их выход искажен. Родительский процесс имеет меньший размер, чем ребенок, поэтому он заканчивается первым. Когда он завершается, ваша оболочка, ожидающая его, просыпается и печатает обычное приглашение. Тем временем дочерний процесс все еще работает. Он печатает больше файлов. Наконец, он завершается. Оболочка не обращает внимания на дочерний процесс (его внук), поэтому оболочка не имеет причины повторно распечатывать приглашение. Посмотрите более внимательно на вывод, который вы получите, и вы сможете найти обычную командную строку, похожую на вывод ls
выше.
Курсор, кажется, ждет, пока вы нажмете клавишу. Когда вы это сделаете, оболочка печатает приглашение, и все выглядит нормально. Но что касается оболочки, все было уже нормально. Вы могли бы набрать еще одну команду раньше. Это выглядело бы немного странно, но оболочка выполнила бы это нормально, потому что он получает только вход от клавиатуры, а не от дочернего процесса, печатающего дополнительные символы на экран.
Если вы используете программу типа top
в отдельном окне консоли, вы можете посмотреть и подтвердить, что обе программы уже закончены, прежде чем вы нажмете Enter.
Ответ 2
Семейство функций Exec
заменяет текущий процесс новым исполняемым файлом.
Чтобы сделать то, что вам нужно, используйте одну из функций fork()
и создайте дочерний процесс Exec
для нового изображения.
[ответ на обновление]
Это делает именно то, что вы сказали: вам не нужно нажимать "enter", чтобы закончить программу: она уже вышла. Оболочка уже выдала приглашение:
[[email protected] ~]$ ./z
before
22397
done
[[email protected] ~]$ 0 << here is the prompt (as well as the pid)
total 5102364
drwxr-xr-x. 2 wally wally 4096 2011-01-31 16:22 Templates
...
Выход из ls
занимает некоторое время, поэтому он зарывает подсказку. Если вы хотите, чтобы вывод отображался в более логичном порядке, добавьте sleep(1)
(или, возможно, дольше) до "done".
Ответ 3
Вам не хватает части, где execl() заменяет вашу текущую программу в памяти на /bin/ls
Я бы предложил посмотреть popen()
, который будет вилкой и исполнить новый процесс, а затем позволить вам читать или писать через трубу. (Или, если вам нужно читать и писать, fork()
самостоятельно, затем exec()
)