Главная страница
Навигация по странице:

  • Удаление дескриптора процесса

  • Дилемма "беспризорного" процесса

  • Планирование выполнения процессов

  • Стратегия планирования

  • Процессы, ограниченные скоростью ввода-вывода и скоростью процессора

  • Приоритет процесса

  • Второе издание


    Скачать 3.09 Mb.
    НазваниеВторое издание
    Дата08.09.2019
    Размер3.09 Mb.
    Формат файлаpdf
    Имя файлаLav_Robert_Razrabotka_yadra_Linux_Litmir.net_264560_original_254.pdf
    ТипДокументы
    #86226
    страница8 из 53
    1   ...   4   5   6   7   8   9   10   11   ...   53
    60
    Глава 3

    Задание завершено настолько, насколько остается возможность передать необхо- димую информацию родительскому процессу.
    Удаление дескриптора процесса
    После возврата из функции do_exit () дескриптор завершенного процесса все еще существует в системе, но процесс находится в состоянии TASK_ZOMBIE и не мо- жет выполняться. Как уже рассказывалось выше, это позволяет системе получить информацию о порожденном процессе после его завершения. Следовательно, завер- шение процесса и удаление его дескриптора происходят в разные моменты времени.
    После того как родительский процесс получил информацию о завершенном порож- денном процессе, структура task_struct порожденного процесса освобождается.
    Семейство функций wait () реализовано через единственный (и достаточно сложный) системный вызов wait4 (). Стандартное поведение этой функции — при- остановить выполнение вызывающей задачи до тех пор, пока один из ее порожден- ных процессов не завершится. При этом возвращается идентификатор PID завершен- ного порожденного процесса. В дополнение к этому, в данную функцию передается указатель на область памяти, которая после возврата из функции будет содержать код завершения завершившегося порожденного процесса.
    Когда приходит время окончательно освободить дескриптор процесса, вызывает- ся функция release_task (), которая выполняет указанные ниже операции.
    • Вызывается функция free_uid () для декремента счетчика ссылок на инфор- мацию о пользователе процесса. В системе Linux поддерживается кэш с инфор- мацией о каждом пользователе, в частности сколько процессов и открытых файлов имеет пользователь. Если счетчик ссылок достигает значения нуль, то пользователь больше не имеет запущенных процессов и открытых файлов, в результате кэш уничтожается.
    • Вызывается функция unhash_process () для удаления процесса из хеш-табли- цы идентификаторов процессов pidhash и удаления задачи из списка задач.
    • Если задача была в состоянии трассировки (ptrace), то родительским для нее снова назначается первоначальный родительский процесс и задача удаляется из списка задач, которые находятся в состоянии трассировки (pirate) данным процессом.
    • В конце концов вызывается функция put_task_struct () для освобождения страниц памяти, содержащих стек ядра процесса и структуру thread_infо, a также освобождается слябовый кэш, содержащий структуру task_struct.
    На данном этапе дескриптор процесса, а также все ресурсы, которые принадле- жали только этому процессу, освобождены.
    Дилемма "беспризорного" процесса
    Если родительский процесс завершается до того, как завершаются вес его потом- ки, то должен существовать какой-нибудь механизм назначения нового родительского процесса для порожденных, иначе процессы, у которых нет родительского, навсегда останутся в состоянии зомби, что будет зря расходовать системную память. Решение этой проблемы было указано выше: новым родительским процессом становится или
    Управление процессами 61
    какой-либо один поток из группы потоков завершившегося родительского процес са, или процесс i n i t . При выполнении функции d o _ e x i t () вызывается функция n o t i f y _ p a r e n t (), которая в свою очередь вызывает f o r g e t _ o r i g i n a l p a r e n t ()
    для осуществления переназначения родительского процесса (reparent), как показано ниже.
    struct task_struct *р, *reaper = father;
    struct list_head *list;
    if (father->exit_signal != -1)
    reaper = prev_thread(reaper);
    else reaper = child_reaper;
    if (reaper == father)
    reaper = child_reaper;
    Этот программный код присваивает переменной r e a p e r указатель на другое зада ние в группе потоков данного процесса. Если в этой группе потоков нет другого за- дания, то переменной r e a p e r присваивается значение переменной c h i l d _ r e a p e r ,
    которая содержит указатель на процесс i n i t . Теперь, когда найден подходящий ро- дительский процесс, нужно найти все порожденные процессы и установить для них полученное значение родительского процесса, как показано ниже.
    list_for_each(list, &father->children) {
    р = list_entry(list, struct task_struct, sibling);
    reparent_thread(p, reaper, child_reaper);
    }
    list_for_each (list, sfather->ptrace__children) {
    p = list_entry(list, struct task:_struct, ptrace_list);
    reparent_thread(p, reaper, child_reaper);
    }
    В этом программном коде организован цикл по двум спискам: по списку порож- денных процессов child list и по списку порожденных процессов, находящихся в со- стоянии трассировки другими процессами ptraced child list. Основная причина, по которой используется именно два списка, достаточно интересна (эта новая особен- ность появилась в ядрах серии 2.6). Когда задача находится в состоянии ptrace, для нее временно назначается родительским тот процесс, который осуществляет от- ладку (debugging). Когда завершается истинный родительский процесс для такого задания, то для такой дочерней задачи также нужно осуществить переназначение родительского процесса. В ядрах более ранних версий это приводило к необходимо- сти организации цикла по всем заданиям системы для поиска порожденных процессов.
    Решение проблемы, как было указано выше, — это поддержка отдельного списка для порожденных процессов, которые находятся в состоянии трассировки, что уменыша- ет число операций поиска: происходит переход от поиска порожденных процессов по всему списку задач к поиску только по двум спискам с достаточно малым числом элементов.
    Когда для процессов переназначение родительского процесса прошло успешно,
    больше нет риска, что какой-либо процесс навсегда останется в состоянии зомби.
    62 Глава 3

    Процесс I n i t периодически вызывает функцию wait () для всех своих порожден- ных процессов и, соответственно, удаляет все зомби-процессы, назначенные ему.
    Резюме
    В этой главе рассмотрена важная абстракция операционной системы — процесс.
    Здесь описаны общие свойства процессов, их назначение, а также представлено сравнение процессов и потоков. Кроме того, описывается, как операционная си- стема Linux хранит и представляет информацию, которая относится к процес- сам (структуры t a s k _ s t r u c t и thread_infо), как создаются процессы (вызовы clone () и fork ()), каким образом новые исполняемые образы загружаются в адрес- ное пространство (семейство вызовов exec ()), иерархия процессов, каким образом родительский процесс собирает информацию о своих потомках (семейство функций wait ()) и как в конце концов процесс завершается (непроизвольно или с помощью вызова exit ()).
    Процесс — это фундаментальная и ключевая абстракция, которая является осно- вой всех современных операционных систем и, в конце концов, причиной, по кото- рой вообще существуют операционные системы (чтобы выполнять программы).
    В следующей главе рассказывается о планировании выполнения процессов — из- ящной и интересной функции ядра, благодаря которой ядро принимает решение,
    какие процессы должны выполняться, в какое время и в каком- порядке.
    Управление процессами 63

    Планирование
    выполнения процессов
    В
    предыдущей главе были рассмотрены процессы— абстракция операционной системы, связанная с активным программным кодом. В этой главе представлен планировщик процессов — код, который позволяет процессам выполняться.
    Планировщик (scheduler) — это компонент ядра, который выбирает из всех про- цессов системы тот, который должен выполняться следующим. Таким образом, пла- нировщик (или, как еще его называют, планировщик выполнения процессов) можно рассматривать как программный код, распределяющий конечные ресурсы процес- сорного времени между теми процессами операционной системы, которые могут выполняться. Планировщик является основой многозадачных (multitasking) операцион- ных систем, таких как ОС Linux. Принимая решение о том, какой процесс должен выполняться следующим, планировщик несет ответственность за наилучшее исполь- зование ресурсов системы и создает впечатление того, что несколько процессов вы- полняются одновременно.
    Идея, лежащая в основе планирования выполнения процессов, достаточно про- ста. При наличии готовых к выполнению процессов, для того чтобы лучше исполь- зовать процессорное время, необходимо, чтобы всегда выполнялся какой-нибудь процесс. Если в системе процессов больше, чем процессоров, то некоторые процес- сы будут выполняться не во все моменты времени. Эти процессы готовы к выполне-
    нию (runnable). Исходя из информации о наборе готовых к выполнению процессов,
    выбор того процесса, который должен выполняться в следующий момент времени, и есть то фундаментальное решение, которое принимает планировщик.
    Многозадачные операционные системы— это те, которые могут выполнять по- переменно или одновременно несколько процессов. На однопроцессорной машине такие системы создает иллюзию того, что несколько процессов выполняются одно- временно. На многопроцессорной машине они позволяют процессам действительно выполняться параллельно на нескольких процессорах. На машинах любого типа эти системы позволяют процессам выполняться в фоновом режиме и не занимать про- цессорное время, если нет соответствующей работы. Такие задания, хотя и находят- ся в памяти, но не готовы к выполнению. Вместо этого данные процессы используют ядро, чтобы блокироваться до тех пор, пока не произойдет некоторое событие (ввод с клавиатуры, приход данных по сети, наступление некоторого момента времени в будущем и т.д.). Следовательно, ОС Linux может содержать 100 процессов в памяти,
    но только один из них будет в исполняемом состоянии.

    Многозадачные (multitasking) операционные системы бывают двух видов: систе- мы с кооперативной (cooperative) многозадачностью и системы с вытесняющей (preemptive,
    преемптивной) многозадачностью. Операционная система Linux, так же как и большин- ство вариантов ОС Unix и других современных операционных систем, обеспечивает вытесняющую многозадачность. В системе с вытесняющей многозадачностью реше- ние о том, когда один процесс должен прекратить выполнение, а другой возобно- вить его, принимает планировщик. Событие, заключающееся в принудительном за- мораживании выполняющегося процесса, называется вытеснением (preemption) этого процесса. Период времени, в течение которого процесс выполняется перед тем, как будет вытеснен, известен заранее. Этот период называется квантом времени (timesiice)
    процесса. В действительности квант времени соответствует той части процессорно- го времени, которая выделяется процессу. С помощью управления величинами кван- тов времени процессов планировщик принимает также и глобальное решение о пла- нировании работы всей системы. При этом, кроме всего прочего, предотвращается возможность монопольного использования ресурсов всей системы одним процессом.
    Как будет показано далее, величины квантов времени в операционной системе Linux рассчитываются динамически, что позволяет получить некоторые интересные пре- имущества.
    В противоположность рассмотренному выше типу многозадачности, в системах с
    кооперативной многозадачностью процесс продолжает выполняться до тех пор, пока он добровольно не примет решение о прекращении выполнения. Событие, связанное с произвольным замораживанием выполняющегося процесса, называется передачей
    управления (yielding). У такого подхода очень много недостатков: планировщик не мо- жет принимать глобальные решения относительно того, сколько процессы должны выполняться; процесс может монополизировать процессор на большее время, чем это необходимо пользователю; "зависший" процесс, который никогда не передает управление системе, потенциально может привести к неработоспособности систе- мы. К счастью, большинство операционных систем, разработанных за последнее де- сятилетие, предоставляют режим вытесняющей моногозадачности. Наиболее извест- ным исключением является операционная система Mac OS версии 9 и более ранних версий. Конечно, операционная система Unix имеет вытесняющую многозадачность с момента своего создания.
    При разработке ядер ОС Linux серии 2.5, планировщик ядра был полностью реконструирован. Новый тип планировщика часто называется 0(1)-плаиировщиком
    (0(1) scheduler) в связи с соответствующим масштабированием времени выполнения алгоритма планирования
    1
    . Этот планировщик позволяет преодолеть недостатки предыдущих версий планировщика ядра Linux и обеспечить расширенную функцио- нальность, а также более высокие характеристики производительности. В этой главе будут рассмотрены основы работы планировщиков, как эти основы использованы в
    О(1)-планировщике, а также цели создания 0(1)-планировшика, его устройство, прак- тическая реализация, алгоритмы работы и соответствующие системные вызовы.
    1
    Обозначение О(1) — это пример обозначения "большого О". Практически, эта запись означает,
    что планировщик может выполнить все свои действии за постоянное время, независимо от объ- ема входных данных. Полное объяснение того, что такое обозначение "большого О", приведено в приложении В, "Сложность алгоритмов".
    66 Глава 4

    Стратегия планирования
    Стратегия (policy) планирования— это характеристики поведения планировщи- ка, которые определяют, что и когда должно выполняться. Стратегия планирования определяет глобальный характер поведения системы и отвечает за оптимальное ис- пользование процессорного времени. Таким образом, это понятие очень важное.
    Процессы, ограниченные скоростью
    ввода-вывода и скоростью процессора
    Процессы можно классифицировать как те, которые ограничены скоростью ввода-вы-
    вода (I/0-bound), и те, которые ограничены скоростью процессора (processor-bound). К пер- вому типу относятся процессы, которые большую часть своего времени выполнения тратят на отправку запросов на ввод-вывод информации и на ожидание ответов на эти запросы. Следовательно, такие процессы часто готовы к выполнению, но могут выполняться только в течение короткого периода времени, так как в конце концов они блокируются в ожидании выполнения ввода-вывода (имеются в виду не только дисковые операции ввода-вывода, но и любой другой тип ввода-вывода информации,
    как, например, работа с клавиатурой).
    Процессы, ограниченные скоростью процессора, наоборот, большую часть вре- мени исполняют программный код. Такие процессы обычно выполняются до того момента, пока они не будут вытеснены, так как эти процессы не блокируются в ожи- дании на запросы ввода-вывода. Поскольку такие процессы не влияют на скорость ввода-вывода, то для обеспечения нормальной скорости реакции системы не требу- ется, чтобы они выполнялись часто. Стратегия планирования процессов, ограни- ченных скоростью процессора, поэтому предполагает, что такие процессы должны выполняться реже, но более продолжительный период времени. Конечно, оба эти класса процессов взаимно не исключают друг друга. Пример процесса, ограниченно- го скоростью процессора, — это выполнение бесконечного цикла.
    Указанные классификации не являются взаимно исключающими. Процессы мо- гут сочетать в себе оба типа поведения: сервер системы X Windows — это процесс,
    который одновременно интенсивно загружает процессор и интенсивно выполняет операции ввода-вывода. Некоторые процессы могут быть ограничены скоростью ввода-вывода, но время от времени начинают выполнять интенсивную процессор- ную работу. Хороший пример — текстовый процессор, который обычно ожидает на- жатия клавиш, но время от времени может сильно загружать процессор, выполняя проверку орфографии.
    Стратегия планирования операционной системы должна стремиться к удо- влетворению двух несовместных условий: обеспечение высокой скорости реакции процессов (малого времени задержки, low latency) и высокой производительности
    (throughput). Для удовлетворения этим требованиям часто в планировщиках при- меняются сложные алгоритмы определения наиболее подходящего для выполнения процесса, которые дополнительно гарантируют, что все процессы, имеющие более низкий приоритет, также будут выполняться. В Unix-подобных операционных си- стемах стратегия планирования направлена на то, чтобы процессы, ограниченные скоростью ввода-вывода, имели больший приоритет. Использование более высокого приоритета для процессов, ограниченных скоростью ввода-вывода, приводит к уве-
    Ппэнировэние выполнения процессов 67
    личению скорости реакции процессов, так как интерактивные программы обычно ограничиваются скоростью ввода-вывода. В операционной системе Linux для обе- спечения хорошей скорости реакции интерактивных программ применяется опти- мизация по времени оклика (обеспечение малого времени задержки), т.е. процессы,
    ограниченные скоростью ввода-вывода, имеют более высокий приоритет. Как будет видно далее, это реализуется таким образом, чтобы не пренебрегать и процессами,
    ограниченными скоростью процессора.
    Приоритет процесса
    Наиболее широко распространенным типом алгоритмов планирования является планирование с управлением по приоритетам (priority-based). Идея состоит в том, что- бы расположить процессы по порядку в соответствии с их важностью и необходи- мостью использования процессорного времени. Процессы с более высоким при- оритетом будут выполняться раньше тех, которые имеют более низкий приоритет,
    в то время как процессы с одинаковым приоритетом планируются на выполнение циклически (по кругу, round-robin), т.е. периодически один за другим. В некоторых операционных системах, включая Linux, процессы с более высоким приоритетом получают также и более длительный квант времени. Процесс, который готов к вы- полнению, у которого еще не закончился квант времени и который имеет наиболь- ший приоритет, будет выполняться всегда. Как операционная система, так и пользо- ватель могут устанавливать значение приоритета процесса и таким образом влиять на работу планировщика системы.
    В операционной системе Linux используется планировщик с динамическим управ-
    лением по приоритетам (dynamic priority-based), который основан на такой же идее.
    Основной принцип состоит в том, что вначале устанавливается некоторое началь- ное значение приоритета, а затем планировщик может динамически уменьшать или увеличивать это значение приоритета для выполнения своих задач. Например, ясно,
    что процесс, который тратит много времени на выполнение операций ввода-вывода,
    ограничен скоростью ввода-вывода. В операционной системе Linux такие процессы получают более высокое значение динамического приоритета. С другой стороны,
    процесс, который постоянно полностью использует свое значение кванта време- ни, — это процесс, ограниченный скоростью процессора. Такие процессы получают меньшее значение динамического приоритета.
    В ядре Linux используется два различных диапазона приоритетов. Первый — это параметр nice, который может принимать значения в диапазоне от -20 до 19, по умолчанию значение этого параметра равно 0. Большее значение параметра nice со- ответствует меньшему значению приоритета — необходимо быть более тактичным к другим процессам системы (пicе— англ. тактичный, хороший). Процессы с меньшим значением параметра nice (большим значением приоритета) выполняются раньше процессов с большим значением niie (меньшим приоритетом). Значение параметра
    nice позволяет также определить, насколько продолжительный квант времени полу- чит процесс. Процесс со значением параметра nice равным -20 получит квант вре- мени самой большой длительности, в то время как процесс со значением параметра
    nice равным 19 получит наименьшее значение кванта времени. Использование пара- метра nice — это стандартный способ указания приоритетов процессов для всех Unix- подобных операционных систем.
    68 Глава 4

    Второй диапазон значений приоритетов— это приоритеты реального времени
    (real-time priority), которые будут рассмотрены ниже. По умолчанию диапазон зна- чений этого параметра лежит от 0 до 99. Все процессы реального времени имеют более высокий приоритет по сравнению с обычными процессами. В операционной системе Linux приоритеты реального времени реализованы в соответствии со стан- дартом POSIX. В большинстве современных Unix-систем они реализованы по анало- гичной схеме.
    1   ...   4   5   6   7   8   9   10   11   ...   53


    написать администратору сайта