В результате выполнения этой функции создается открытый файловый дескриптор канала (pipe), из которого породивший процесс может (mode
STDOUT_FILENO) или в который может (mode = «w») писать (стандартный поток ввода дочернего процесса STDIN_FILENO) стандартным образом, как это делается для типа FILE (в частности, с отработкой ситуации EOF).Рассмотрим следующий пример. Конечно, посимвольный ввод/вывод — это не лучшее решение, и здесь мы используем его только для простоты:
int main(int argc, char** argv) {
FILE* f = popen("ls -l", "r");
if (f == NULL) perror("popen"), exit(EXIT_FAILURE);
char c;
while((с = fgetc(f)) != EOF )
cout << (islower(с) ? toupper(с) : c);
pclose(f);
return EXIT_SUCCESS;
}
Новый процесс выполняется с тем же окружением, что и родительский. Процесс, указанный в команде, запускается примерно следующим эквивалентом:
spawnlp(P_NOWAIT, shell_command, shell_command, "-с", command, (char*)NULL);
где shell_command
/bin/sh. В этом кроется причина возможного различия в выполнении вызовов system() и popen().Если popen()
NULL, то выполнение прошло успешно. В противном случае устанавливается errno: EINVAL — недопустимый аргумент mode, ENOSYS — в системе не выполняется программа менеджера каналов. После завершения работы с каналом, созданным popen(), он должен быть закрыт парной операцией pclose().При использовании system()
Клонирование процесса
Вызов fork()
fork() является одной из самых базовых конструкций всего UNIX-программирования. Его толкованию посвящено столько страниц в литературе, сколько не уделено никакому другому элементу API. Синтаксис этого вызова (проще по синтаксису не бывает, сложнее по семантике — тоже):#include
pid_t fork(void);
Действие вызова fork()
• Порождается дочерний процесс, которому системой присваивается новое уникальное значение PID.
• Дочерний процесс получает собственные копии файловых дескрипторов, открытых в родительском процессе в точке выполнения fork()
• Для дочернего процесса его значения tms_utime
tms_stime, tms_cutime и tms_cstime устанавливаются в значение ноль. Выдержки (alarms) для этих таймеров, установленные к этому времени в родительском процессе, в дочернем процессе очищаются.Сигнальные маски (подробнее об этом будет рассказано ниже) для дочернего процесса инициализируются пустыми сигнальными наборами (независимо от сигнальных масок, установленных родительским процессом).
Если вызов функции завершился неудачно, функция возвращает -1 и устанавливает errno
EAGAIN — недостаточно системных ресурсов; ENOMEM — процессы требуют большее количество памяти, чем доступно в системе; ENOSYS — функция fork() не реализуется в этой модели памяти, например в физической модели адресации памяти (напомним, что QNX — многоплатформенная ОС и число поддерживаемых ею платформ все возрастает).