pid_one = fork() ;
if( 0 == pid_one ) /*child process block */
Вы не проверяете fork(2)
на наличие ошибки, что вполне реально. (Пользователь может столкнуться с пределом RLIMIT_NPROC
, kernel.threads-max
, нехваткой памяти для хранения структур задач и т. Д.)
Более идиоматическое использование fork(2)
выглядит так:
if(-1 == (pid = fork()) {
perror("fork");
exit(1); /* or return -1 or similar */
} else if (0 == pid) {
/* executing as child */
} else {
/* parent, pid is child */
}
execvp(cmd_two_tokens[0] , cmd_two_tokens);
/* if execvp returns then if must have failed */
printf("Unknown Command \n ");
Обратите внимание, что существует много причин, по которым execvp(3)
может потерпеть неудачу; просто печать «Неизвестная команда» может оставить ваших пользователей очень запутанными в будущем. Было бы лучше позвонить по номеру perror("execvp");
и дать вашим пользователям возможность узнать реальную причину, по которой их execvp(3)
звонок не удался.
waitpid ( -1 , &status ,WNOHANG);
Использование WNOHANG
здесь может быть опасно; если система работает «правильно», ваш родитель может получить этот код еще до того, как у ребенка появится шанс начать выполнение. Поскольку вы просили, чтобы он немедленно вернулся, если ни один ребенок не вышел, вероятно, когда он, наконец, выйдет, ребенок превратится в зомби - ваш код не использует возможность снова ждать ребенка.
Я не уверен, каково лучшее решение: если вы используете SA_NOCLDWAIT
до sigaction(2)
, чтобы полностью не создавать зомби, у вас не будет возможности когда-либо собрать статус выхода ребенка. Установка обработчика сигнала SIGCHLD
может помешать остальной части процесса; у ваших клиентов может быть причина установить это самостоятельно. Использование блокировки waitpid(2)
может остановить обработку в другом месте. А использование неблокирующего waitpid(2)
означает, что вам все равно придется собирать статус ребенка иногда , возможно, путем опроса. (Но вы не можете использовать -1
для pid
в этом случае, так как вы можете случайно получить другой дочерний процесс.)