Управление процессами
Определение процесса. Основные понятия Процесс совокупность машинных команд и данных, которая исполняется в рамках вычислительной системы и обладает правами на владение некоторым набором ресурсов. Ресурсы могут принадлежать только одному процессу, либо ресурсы могут разделяться между процессами разделяемые ресурсы. предварительная декларация до начала выполнения динамическое пополнение списка принадлежащих процессу ресурсов Выделение ресурсов процессу Количество допустимых процессов в системе ресурс ВС.
Жизненный цикл процесса Жизненный цикл процесса в системе: Образование (порождение) процесса Обработка (выполнение) процесса Ожидание (по тем или иным причинам) постановки на выполнение Завершение процесса Типовые этапы обработки процесса в системе Основной из задач ОС является поддержание жизненного цикла процесса.
Модельная ОС 1. Буфер ввода процессов (БВП) пространство, в котором размещаются и хранятся сформированные процессы с момента их образования, до момента начала выполнения. 2. Буфер обрабатываемых процессов (БОП) буфер для размещения процессов, находящихся в системе в мультипрограммной обработке.
Модель пакетной однопроцессной системы Обработка ЦПЗавершение 12 0.Поступление процесса в очередь на начало обработки ЦП (процесс попадает в БВП) 1.Начало обработки процесса на ЦП (из БВП в БОП) 2.Завершение выполнения процесса, освобождение системных ресурсов. Ожидание начала обработки 0
Модель пакетной мультипроцессной системы БОП БВП Обработка ЦП Завершение 1 4 Ожидание начала обработки 0 Ожидания операции в/в 2 3 Очередь на выполнение 5
БОП БВП Модель ОС с разделением времени Обработка ЦП Завершение 1 4 Ожидание начала обработки 0 Ожидания операции в/в 2 3 Очередь на выполнение 5 6
Модель ОС с разделением времени (модификация) Диск свопинг БОП БВП Обработка ЦП Завершение 1 4 Ожидание начала обработки 0 Ожидания операции в/в 2 3 Очередь на выполнение 5 6
Типы процессов «Полновесные процессы» это процессы, выполняющиеся внутри защищенных участков оперативной памяти, то есть имеющие собственные виртуальные адресные пространства для статических и динамических данных. «Легковесные процессы» нити работают в мультипрограммном режиме одновременно с активировавшей их задачей и используют ее виртуальное адресное пространство. «полновесные» процессы «легковесные» процессы
Типы процессов Однонитевая организация процесса «один процесс одна нить»: процесс нить Многонитевая организация процесса: процесс нить Причина использования многонитевой организации уменьшение количества смены контекстов.
Понятие «процесс» Понятие «процесс» включает в себя следующее: исполняемый код собственное адресное пространство, которое представляет собой совокупность виртуальных адресов, которые может использовать процесс ресурсы системы, которые назначены процессу ОС хотя бы одну выполняемую нить
Контекст процесса Контекст процесса совокупность данных, характеризующих актуальное состояние процесса. Пользовательская составляющая текущее состояние программы (совокупность машинных команд, размещенных в ОЗУ) Системная составляющая информация идентификационного характера (PID процесса, PID «родителя»…) информация о содержимом регистров (РОН, индексные регистры, флаги...) информация, необходимая для управления процессом (состояние процесса, приоритет....)
Процессы в UNIX 1.Ситемно-ориентированные определения процесса 2.Контекст процесса 3.1.Пользовательская составляющая (тело процесса) 3.2.Разделение сегмента кода 3.3.Аппаратная составляющая 3.4.Системная составляющая
Определение процесса Unix Объект, зарегистрированный в таблице процессов ОС Объект, порожденный системным вызовом fork() Процесс
Процесс в UNIX объект, зарегистрированный в таблице процессов UNIX. Определение процесса в UNIX PID Системный Аппаратный Пользовательский (тело процесса) адресное пространство ядра адресное пространство процесса Таблица процессов Контекст процесса Идентификатор процесса (PID)
Контекст процесса Пользовательская составляющая (тело процесса) Аппаратная составляющая Системная составляющая Сегмент кода Сегмент данных Машинные команды Неизменяемые константы Статические данные Разделяемая память Стек Статические переменные Фактические параметры в функциях Автоматические переменные Динамическая память Контекст процесса
Разделение сегмента кода Сегмент кода программы Сегмент данных 1... Процесс 1 Сегмент данных 2 Сегмент данных N Для идентичных процессов имеется возможность запускать только один сегмент кода: Процесс 2Процесс N
Контекст процесса счетчик команд регистр состояния процессора аппарат виртуальной памяти регистры общего назначения и т. д. все регистры и аппаратные таблицы ЦП, используемые активным или исполняемым процессом Пользовательская составляющая (тело процесса) Аппаратная составляющая Системная составляющая Контекст процесса
идентификатор родительского процесса текущее состояние процесса приоритет процесса реальный и эффективный идентификаторы пользователя-владельца реальный и эффективный идентификатор идентификатор группы, к которой принадлежит владелец список областей памяти таблица открытых файлов процесса информация об установленной реакции на тот или иной сигнал информация о сигналах, ожидающих доставки в данный процесс сохраненные значения аппаратной составляющей Пользовательская составляющая (тело процесса) Аппаратная составляющая Системная составляющая Контекст процесса
Базовые средства организации и управления процессами 1.Второе определение процесса UNIX 2.Создание нового процесса. Системный вызов fork() 3.Семейство системных вызовов exec() 4.Использование схемы fork() exec() 5.Завершение процесса. Системный вызов exit() 6.Получение информации о завершении потомка. Системный вызов wait()
Процесс в UNIX это объект, порожденный системным вызовом fork(). Второе определение процесса в UNIX Данный системный вызов является единственным стандартным средством порождения процессов в системе UNIX. Системный вызов специальная функция, позволяющая процессу обращаться к ядру ОС за выполнением тех или иных действий.
Создание нового процесса #include pid_t fork ( void ); При удачном завершении возвращается: сыновнему процессу значение 0 родительскому процессу PID порожденного процесса При неудачном завершении возвращается –1, код ошибки устанавливается в переменной errno
Создание нового процесса Заносится новая запись в таблицу процессов Новый процесс получает уникальный идентификатор Создание контекста для сыновнего процесса При выполнении системного вызова fork()
Создание нового процесса Окружение Файлы, открытые в процессе-отце Способы обработки сигналов Разрешение переустановки эффективного идентификатора пользователя Разделяемые ресурсы процесса-отца Текущий рабочий каталог и домашний каталоги … Составляющие контекста, наследуемые при вызове fork()
Создание нового процесса Идентификатор процесса (PID) Идентификатор родительского процесса (PPID) Сигналы, ждущие доставки в родительский процесс Время посылки ожидающего сигнала, установленное системным вызовом alarm() Блокировки файлов, установленные родительским процессом Составляющие контекста, не наследуемые при вызове fork()
fork() Потомок: выполняются операторы в else-секции Предок: выполняются операторы в if-секции PID = 2757 main() { … if ( (pid=fork()) > 0 ) { … } else { … } } сегмент кода PID = 2757 main() { … if ( (pid=fork()) > 0 ) { … } else { … } } сегмент кода PID = 2760 main() { … if ( (pid=fork()) > 0 ) { … } else { … } } сегмент кода Схема создания нового процесса
Пример int main ( int argc, char **argv ) { printf ( "PID = %d; PPID = %d \n", getpid(), getppid() ); fork (); printf ( "PID = %d; PPID = %d \n", getpid(), getppid() ); return 0; }
Семейство системных вызовов exec() #include int execl (const char *path, char *arg0, …, char *argn, 0); path имя файла, содержащего исполняемый код программы arg0 имя файла, содержащего вызываемую на выполнение программу arg1, …, argn аргументы программы, передаваемые ей при вызове Возвращается: в случае ошибки –1
main() { execl(/bin/ls, ls, l, (char*)0); } PID = 2760 main() { // реализация программы ls } exec() Семейство системных вызовов exec() Схема работы системного вызова exec()
Семейство системных вызовов exec() Сохраняются: Идентификатор процесса Идентификатор родительского процесса Таблица дескрипторов файлов Приоритет и большинство атрибутов Изменяются: Режимы обработки сигналов Эффективные идентификаторы владельца и группы Файловые дескрипторы (закрытие некоторых файлов)
Пример #include int main ( int argc, char **argv ) { … /* тело программы */ … execl ( /bin/ls, ls, -l, (char*) 0 ); /* или execlp ( ls,ls, -l, (char*) 0 ); */ printf ( это напечатается в случае неудачного обращения к предыдущей функции, к примеру, если не был найден файл ls.\n ); … }
Использование схемы fork-exec fork() exec() main () { // реализация программы } PID = 2760 PID = 2757 main() { if((pid=fork())== 0) { execl(/bin/ls, ls, -l, (char*)0); } else {…} } main() { if((pid=fork())== 0) { execl(/bin/ls, ls, -l, (char*)0); } else {…} } main() { if((pid=fork())== 0) { execl(/bin/ls, ls, -l, (char*)0); } else {…} } PID = 2757PID = 2760
Завершение процесса Системный вызов _exit() Выполнение оператора return, входящего в состав функции main() Получение сигнала
Завершение процесса #include void _exit ( int status ); status код возврата программы, имеющий (как правило) значение: 0 при успешном завершении не 0 при неудаче (возможно, номер варианта) Сам вызов никогда не завершается неудачно, поэтому у него нет возвращаемого значения.
Завершение процесса Освобождается сегмента кода и сегмента данных процесса Закрываются все открытые дескрипторы файлов Если у процесса имеются потомки, их предком назначается процесс с идентификатором 1 Освобождается большая часть контекста процесса (кроме статуса завершения и статистики выполнения) Процессу-предку посылается сигнал SIGCHLD
#include pid_t wait ( int *status ); Получение информации о завершении своего потомка status по завершению содержит: в старшем байте код завершения процесса-потомка (пользовательский код завершения процесса) в младшем байте индикатор причины завершения процесса-потомка, устанавливаемый ядром UNIX (системный код завершения процесса) Возвращается: PID завершенного процесса или –1 в случае ошибки или прерывания
Получение информации о завершении своего потомка Приостановка родительского процесса до завершения (остановки) какого-либо из потомков После передачи информации о статусе завершения предку, все структуры, связанные с процессом-«зомби» освобождаются, удаляется запись о нем из таблицы процессов
Пример. Использование системного вызова wait() #include int main ( int argc, char **argv ) { int i; for ( i=1; i 0 ) { wait( &status ); printf( process-father\n ); continue; } execlp ( argv[i], argv[i], 0 ); exit (); }
Готов к выполнению очередь готовых процессов планирование процессов Создан fork() Блокирован ожидает внешнего события внешнее событие прерывание Зомби exit()wait() Жизненный цикл процессов Выполняется В режиме ядра В пользовательском режиме
Формирование процессов 0 и 1 1.Начальная загрузка системы 2.Инициализация системы 2.1.Создание процесса Создание процесса 1
Начальная загрузка Начальная загрузка это загрузка ядра системы в основную память и ее запуск. Чтение нулевого блока системного устройства аппаратным загрузчиком Поиск и считывание в память файла /unix Запуск на исполнение файла /unix
Инициализация системы Установка системных часов Формирование диспетчера памяти Формирование значения некоторых структур данных Инициализация процесса с номером 0 Нулевой процесс не имеет кодового сегмента Нулевой процесс существует в течении всего времени работы системы Контекст процесса 0
Инициализация системы Создание ядром первого процесса Копируется процесс 0 (т.е нет области кода) Создание области кода процесса 1 Копирование в область кода процесса 1 программы, реализующей системный вызов exec(), который необходим для выполнения программы /etc/init Контекст процесса 0 Контекст процесса 1 Контекст процесса exec() 1 Контекст процесса Кодовый сегмент 1
Инициализация системы Выполнение программ диспетчера Запуск exec() для замены команды процесса 1 кодом из файла /etс/init Подключение интерпретатора команд к системной консоли Создание многопользовательской среды getty Терминал 1 Терминал 2 Терминал N … init 1 init
init shell Выполняет пользовательские программы Ввод пароля Верный пароль Неверный пароль Окончание работы fork()/ exec() init После окончания работы shell создает новый getty getty Печатает login: и ожидает входа в систему login Запрашивает пароль и проверяет его Схема дальнейшей работы системы