Из других важных атрибутов процесса отметим [9] Здесь используется терминология [7]; терминология и аббревиатуры для различных клонов UNIX несколько различаются между собой в описывающих их литературных источниках.
:
• PPID (Parent Process ID) — PID процесса, породившего данный процесс. Таким образом, все процессы в системе включены в единую древовидную иерархию.
• TTY — терминальная линия: терминал или псевдотерминал, ассоциированный с процессом. Если процесс становится процессом-демоном, то он отсоединяется от своей терминальной линии и не имеет ассоциированной терминальной линии. (Запуск процесса как фонового — знак «&» в конце командной строки — не является достаточным основанием для отсоединения процесса от терминальной линии.)
• RID и EUID — реальный и эффективный идентификаторы пользователя. Эффективный идентификатор служит для определения прав доступа процесса к системным ресурсам (в первую очередь к файловым системам). Обычно RID и EUID совпадают, но установка флага SUID для исполняемого файла процесса позволяет расширить полномочия процесса.
• RGID и EGID — реальный и эффективный идентификаторы группы пользователей. Как и в случае идентификаторов пользователя, EGID не совпадает с RGID, если установлен флаг SGID для исполняемого файла процесса.
Часто в качестве атрибутов процесса называют и приоритет выполнения. Однако приоритет является атрибутом не процесса (процесс — это статическая субстанция, контейнер), а потока, но если поток единственный (главный, порожденный функцией main()
), его приоритет и есть то, что понимается под «приоритетом процесса».
Созданию процессов (имеется в виду создание процесса из программного кода) посвящено столько описаний [1-9], что детальное рассмотрение этого вопроса было бы лишь пересказом. Поэтому мы ограничимся только беглым перечислением этих возможностей, тем более что в ходе обсуждения нас главным образом интересуют не сами процессы, а потоки, заключенные в адресных пространствах процессов.
Использование командного интерпретатора
Самый простой способ — запустить из программного кода дочернюю копию командного интерпретатора, которому затем передать команду запуска процесса. Для этого используется вызов:
int system(const char* command);
где command
— текстовая строка, содержащая команду, которую предполагается выполнить ровно в том виде, в котором мы вводим ее командному интерпретатору с консоли.
Примечание
Функция имеет еще одну специфическую форму вызова, когда в качестве command
задается NULL
. По коду возврата это позволяет выяснить, присутствует ли (и доступен ли) командный интерпретатор в системе (возвращается 0, если интерпретатор доступен).
На время выполнения вызова system()
вызывающий процесс приостанавливается. После завершения порожденного процесса функция возвращает код завершения вновь созданной копии интерпретатора (или -1, если сам интерпретатор не может быть выполнен), то есть младшие 8 бит возвращаемого значения содержат код завершения выполняемого процесса. Возврат вызова system()
может анализироваться макросом WEXITSTATUS()
, определенным в файле . Например:
#include
int main(void) {
int rc = system("ls");
if (rc == -1) cout << "shell could not be run" << endl;
else
cout << "result of running command is " << WEXITSTATUS(rc) << endl;
return EXIT_SUCCESS;
}
Примечание
Эта функция использует вызов spawnlp()
для загрузки новой копии командного интерпретатора, то есть «внутреннее устройство» должно быть в общем виде вам понятно. Особенностью QNX-реализации является то, что spawnlp()
всегда использует вызов /bin/sh
, независимо от конкретного вида интерпретатора, устанавливаемого переменной окружения SHELL (ksh, bash…). Это обеспечивает независимость поведения родительского приложения от конкретных установок системы, в которой это приложение выполняется.
Вызов system()
является не только простым, но и очень наглядным, делающим код легко читаемым. Программисты часто относятся к нему с пренебрежением [10] Здесь многое зависит от расстановки приоритетов. Если вы хотите, чтобы всякий, читающий ваш код, тут же воскликнул: «Ну и крутой же парень написал такое!», заведомо используйте spawn() . При желании сделать код максимально элегантным используйте fork() , а если ставится задача хорошей читаемости и ясности кода, то очень часто достаточно и system() .
, отмечая множество его недостатков. Однако в относительно простых случаях это может быть оптимальным решением, а недостатки не так и существенны:
Читать дальше
Конец ознакомительного отрывка
Купить книгу