sem11 - Работа с процессами. Перенаправление стандартных потоков. (1114924)
Текст из файла
1Работа с процессами в POSIX-системахПонятие «процесс» наряду с понятием «файл» относится к основным понятиям операционной системы. Под процессом можно понимать программу в стадии выполнения. С процессом в системе связано много атрибутов, например, страницы памяти, занимаемые процессом, или идентификатор пользователя. Процесс использует ресурсы системы, поэтому однаиз основных задач ядра операционной системы — распределение ресурсов между процессами.Каждый процесс имеет своё адресное пространство.
Если в системе в текущий моментесть несколько готовых к выполнению процессов, они работают параллельно. На системе с одним процессором эти процессы разделяют время одного процессора, а на системес несколькими процессорами каждый процесс может выполняться на своём процессоре, иони будут работать действительно параллельно. Параллелизм выполнения вносит принципиально новые моменты по сравнению с обычным последовательным программированием иделает параллельные программы значительно более трудоёмкими в разработке и отладке.1.1 Создание процессаНовый процесс создаётся с помощью системного вызова fork.#include <unistd.h>pid_t fork(void);Вновь созданный (сыновний) процесс отличается только своим идентификатором процессаpid и идентификатором родительского процесса ppid. Кроме того, у нового процесса сбрасываются счётчики использования ресурсов, блокировки файлов и ожидающие сигналы.Сыновний процесс продолжает выполнять тот же код, что и родительский процесс.
Отличить новый процесс от родительского можно только по возвращаемому системным вызовомfork значению. В сыновний процесс возвращается 0, а в родительский процесс возвращается идентификатор сыновнего процесса. Кроме того, функция fork возвращает число -1,когда новый процесс не может быть создан из-за нехватки ресурсов, либо из-за превышениямаксимального разрешённого числа процессов для пользователя или всей системы. Обычнофункция fork используется следующим образом:if ((pid = fork())) < 0) { /* сигнализировать об ошибке */ }else if (!pid) {/* этот фрагмент кода выполняется в сыновнем процессе *//* ...
*/_exit(0);} else {/* а этот фрагмент выполняется в родительском процессе */}Функции getpid, getppid позволяют получить идентификатор текущего или родительского процесса.#include <unistd.h>pid_t getpid(void);pid_t getppid(void);1Функция getpid возвращает идентификатор текущего процесса, а функция getppid возвращает идентификатор родительского процесса. Если родительский процесс завершил своёвыполнение раньше сыновнего, «родительские права» передаются процессу с номером 1 —процессу init. Идентификатор процесса — это положительное число в интервале от 1 до (какправило) 32000. При создании нового процесса система назначает ему новый идентификатор. Когда pid достигнет максимального допустимого значения, счёт начнётся снова с 1.Каждый процесс относится к некоторой группе процессов.
В группу могут объединятьсяпроцессы, выполняющие с точки зрения программиста одно задание. Например, интерпретатор команд может объединить в одну группу процессов все процессы, связанные конвейером.В простейшем случае группа процессов может состоять из единственного процесса. Группапроцессов идентифицируется положительным целым числом, совпадающим с идентификатором одного из процессов в этой группе. Даже после того, как этот процесс завершит работу, идентификатор группы процессов будет действительным до момента, пока не завершитработу последний процесс этой группы процессов.Группа процессов может выступать как одно целое в системных вызовах отправлениясигнала (они будут подробно рассмотрены ниже). Отрицательный идентификатор процессав них обозначает, что сигнал посылается не одному процессу, а всей группе процессов, идентификатор группы которой совпадает с модулем аргумента.
При работе с терминалом выделяются основная и фоновые группы процессов, и нажатие на комбинацию клавиш Ctrl-Cпосылает сигнал SIGINT сразу всей основной группе процессов. Другие сигналы, генерируемые при работе с терминалом (SIGTSTP, SIGQUIT и др.) так же посылаются всей основнойгруппе процессов.Идентификатор группы процесса сохраняется (наследуется) при создании нового процесса с помощью fork. Но, в отличие от идентификатора процесса, идентификатор группыпроцессов можно изменить.#include <sys/types.h>#include <unistd.h>intsetpgid(pid_t pid, pid_t pgid);pid_t getpgid(pid_t pid);Функция getpgid возвращает идентификатор группы процессов процесса с заданнымидентификатором pid. Если аргумент pid равен 0, возвращается информация для текущегопроцесса. В случае ошибки возвращается -1.Функция setpgid помещает процесс pid в группу процессов pgid.
И pid, и pgidмогут быть равны 0, что означает идентификатор текущего процесса. При необходимостисоздаётся новая группа процессов. Если pid не совпадает с идентификатором самого процесса, это должен быть идентификатор одного из сыновних процессов, который ещё не выполнил к этому моменту вызов exec. В случае успешного завершения функция возвращает0. При неудаче функция возвращает -1, а переменная errno устанавливается в код ошибки.EACCES Сыновний процесс, заданный аргументом pid уже выполнил exec.EINVAL Недопустимое значение pgid.ENOSYS Система не поддерживает управление заданиями.EPERMПроцесс, заданный аргументом pid, является лидером сессии, не находитсяв той же самой сессии, что текущий процесс, значение pgid не соответствуетгруппе процессов в той же самой сессии, что текущий процесс.21.2 Замещение тела процессаЧаще всего новый процесс создаётся для того, чтобы запустить на выполнение какуюлибо другую программу.
В системах POSIX другую программу можно запустить, только заменив области памяти текущего процесса. Для этого служат функции семейства exec.#include <unistd.h>extern char **environ;int execve(const char *filename, char *const argv[],char *const envp[]);int execl(const char *path, const char *arg, ...);int execlp(const char *file, const char *arg, ...);int execle(const char *path, const char *arg, ...,char * const envp[]);int execv(const char *path, char *const argv[]);int execvp(const char *file, char *const argv[]);Основной функцией является системный вызов execve.
Все остальные функции используют системный вызов execve.Системный вызов execve запускает программу, заданную аргументом filename. Программа должна быть либо двоичной исполняемой программой, либо скриптом, начинающимся со строки вида#! interpreter [arg]В этом случае интерпретатор interpreter должен быть правильным путём к исполняемому двоичному файлу. Тогда программа будет запущена на выполнение строкой:interpreter [arg] filenameargv — это массив строк — аргументов командной строки, передаваемый новой программе.envp — массив строк вида key=value, который передаётся как окружение в новую программу. И argv и envp должны завершаться нулевым указателем.
Аргументы команднойстроки и переменные окружения доступны из функции main вызванной программы (еслиэто — программа на Си), которая определяется следующим образом:int main(int argc, char *argv[], char *envp[]);Системный вызов execve не возвращает управление вызвавшей его программе в случаеуспеха, поскольку страницы кода, данных и стека процесса замещаются страницами из загружаемой программы.
Запускаемая программа наследует идентификатор процесса pid и всеоткрытые файловые дескрипторы, кроме тех, которые явно помечены флагом FD_CLOEXEC.Очищаются сигналы, ожидающие доставки. Обработчики всех неигнорируемых и не обрабатываемых по умолчанию сигналов сбрасываются в значения по умолчанию.Если текущий процесс трассируется с помощью системного вызова ptrace, послеуспешного вызова execve ему посылается сигнал SIGTRAP.Если у файла запускаемой программы установлен бит SUID, эффективный идентификатор пользователя изменяется на идентификатор владельца данного файла. Аналогично, если3у файла запускаемой программы установлен бит SGID, эффективный идентификатор группыизменяется на идентификатор группы данного файла.Если исполняемый файл использует динамические библиотеки, система вызывает динамический загрузчик, чтобы он подгрузил в адресное пространство процесса необходимые динамические библиотеки.В случае ошибки execve возвращает -1, и переменная errno устанавливается в кодошибки.
Возможные ошибки приведены в таблице.EACCESEPERME2BIGENOEXECEFAULTENAMETOOLONGENOENTENOMEMENOTDIRELOOPETXTBUSYEIOENFILEEMFILE1) Запускаемый файл или интерпретатор скрипта не является регулярным файлом.2) Нет прав на выполнение запускаемого файла или интерпретатораскрипта.3) Файловая система не допускает выполнение файлов.4) Нет права поиска в каком-либо каталоге, входящем в путь кfilename или интерпретатору скрипта.Попытка запустить файл с установленным битом SUID или SGID втрассируемом процессе.Список аргументов слишком велик.Неверный формат исполняемого файла.Какой-либо из аргументов — недопустимый адрес.Аргумент filename слишком длинный.Файл filename или интерпретатор скрипта не существует.Недостаточно памяти ядра.Некоторая компонента пути к файлу filename или интерпретаторускрипта не является каталогом.Слишком много символических ссылок при прослеживании файлаfilename или интерпретатора скрипта.Файл filename или интерпретатор скрипта открыт на запись другимпроцессом.Ошибка ввода/вывода.Достигнуто максимальное количество открытых файлов в системе.Достигнуто максимальное количество открытых файлов для процесса.Таблица 1: Коды ошибок системного вызова execveФункции execvp, execv, execle, execlp, execl являются оболочками над execve.Аргумент arg и последующие аргументы в функциях execl, execlp, execle можнорассматривать как arg0, arg1, .
. . , argn. Все вместе они описывают список указателейна строки, представляющий собой список аргументов для вызываемой программы. По соглашению первый аргумент должен содержать имя запускаемого файла. Список аргументовдолжен завершаться нулевым указателем NULL.Функции execv и execvp принимают массив указателей на строки, которые будут переданы как аргументы в вызываемую программу. По соглашению первый аргумент долженсодержать имя запускаемого файла. Массив аргументов должен завершаться нулевым указателем NULL.Функция execle позволяет задавать окружение для запускаемой программы. Массивуказателей на строки, задающие переменные окружения, должен завершаться нулевым указателем NULL. Адрес массива должен идти следующим параметром функции execle после нулевого указателя, обозначающего конец списка аргументов, передаваемых вызываемой программе. Все другие функции берут переменные окружения из глобальной переменной4environ текущего процесса. Эта переменная содержит все переменные, переданные текущему процессу, и новые переменные окружения, добавленные с помощью вызова putenv.Таким образом, все другие функции наследуют переменные окружения текущего процесса.Функции execlp и execvp ищут файл file в пути поиска, если строка file не содержит символ ’/’.
Путь поиска определяется переменной окружения PATH, а если эта переменная не задана, используется путь по умолчанию :/bin:/usr/bin. Кроме того, этифункции по-особому реагируют на некоторые ошибки.Если в доступе к файлу отказано (вызов execve вернул EACCES), эти функции продолжают поиск в оставшейся части пути поиска. Но если другого файла не найдено, функциивозвращаются с кодом ошибки EACCES).Если формат файла не был распознан (вызов execve вернул ENOEXEC), эти функциивызовут командный интерпретатор с путём к файлу в качестве первого аргумента.
Характеристики
Тип файла PDF
PDF-формат наиболее широко используется для просмотра любого типа файлов на любом устройстве. В него можно сохранить документ, таблицы, презентацию, текст, чертежи, вычисления, графики и всё остальное, что можно показать на экране любого устройства. Именно его лучше всего использовать для печати.
Например, если Вам нужно распечатать чертёж из автокада, Вы сохраните чертёж на флешку, но будет ли автокад в пункте печати? А если будет, то нужная версия с нужными библиотеками? Именно для этого и нужен формат PDF - в нём точно будет показано верно вне зависимости от того, в какой программе создали PDF-файл и есть ли нужная программа для его просмотра.