Процессы и потоки. Основным понятием, связанным с операционными системами, является процесс - абстрактное понятие, описывающее работу программы. Процессом по сути является программа в момент её выполнения. Все остальное базируется на этом понятии. Все современные компьютеры умеют делать несколько дел одновременно. В многозадачной системе процессор переключается между программами, предоставляя каждой от десятков до сотен миллисекунд. При этом, в каждый момент времени процессор занят только одной задачей, но за секунду успевает поработать со многими задачами, создавая иллюзию многозадачности у пользователей. Это называется псевдопараллелизм, в отличие от настоящего параллелизма в многопроцессорных системах (два или более процессора, разделяющих между собой общую физическую память). Модель процесса. В связи с тем, что следить за работой параллельно идущих процессов достаточно сложно, разработчиками была разработана концептуальная модель последовательных процессов, упрощающая процесс слежения. В этой модели все функционирующее на компьютере программное обеспечение, иногда включая собственно саму операционную систему, организованно в виду последовательных процессов, или для краткости, просто процессов. Процессом является выполняемая программа, включая текущее значение счетчика счетчика команд, регистров и переменных. Реальный процессор переключается с процесса на процесс, но для простоты понимания легче рассматривать процессы, идущие параллельно (псевдопараллельно). Переключение процессора между процессами называется многозадачностью или мультипрограммированием. На рисунке а) представлена схема компьютера, работающего с четырьмя программами. На рисунке б) представлены четыре процесса, каждый со своей управляющей логикой (то есть, логическим счетчиком команд), идущие независимо друг от друга. Разумеется, на самом деле существует только один физический счетчик команд, в который загружается логический счетчик команд текущего процесса. Когда время, отведенное процессу, заканчивается, физический счетчик команд сохраняется в логическом счетчике команд процесса в памяти. На рисунке в) видно, что за достаточно большой промежуток времени изменилось состояние всех четырех процессов, но в каждый конкретный момент времени в действительности работает только один процесс. Различие между процессом и программой трудноуловимо, но тем не менее оно имеет принципиальное значение. Процесс - это активность некоторого рода. У него есть программа, входные и выходные параметры, а также состояние. Один процессор может переключаться между различными процессами, используя некий алгоритм планирования для определения момента переключения от одного процесса к другому. Создание процесса. Завершение процесса. Создание процесса. Основные события, приводящие к созданию процесса: ○ Инициализация системы ○ Выполнение изданного работающим процессом системного запроса на создание процесса ○ Запрос пользователя на создание нового процесса ○ Инициирование пакетного задания Обычно, при загрузке системы создаются несколько процессов, некоторые из которых являются высокоприоритетными, т.е. обеспечивающими взаимодействие с пользователем и выполняющими заданную работу. Остальные процессы являются фоновыми, они не связаны с конкретными пользователями, но выполняют особые функции. Некоторые из них активизируются только в определенный момент, по мере появления задач. Такие процессы называются демонами. С технической точки зрения, во всех случаях новый процесс формируется одинаково: текущий процесс выполняет системный запрос на создание нового процесса. Текущим процессом может быть любой процесс, будь то системный или запущенный пользователем. Системный запрос заставляет создать новый процесс, а также содержит информацию о программе, которую нужно запустить в этом процессе. Для создания нового процесса операционной системе необходимо выполнить определенную последовательность действий: - присвоить новому процессу уникальный идентификатор, т.е. занести новую запись в таблицу процессов; - выделить пространство для процесса, т.е. выделить адресное пространство для всех элементов образа процесса; - инициализировать управляющий блок процесса; - поместить процесс в список «готовых» или «готовых приостановленных процессов»; - загрузить часть кодов и данных процесса в оперативную память. В UNIX существует только один системный запрос, направленный на создание процесса: fork. Этот запрос создает дубликат вызываемого процесса. После выполнения запроса fork двум процессам родительскому и дочернему - соответствуют одинаковые образы памяти, строки окружения и открытые файлы. Обычно, дочерний процесс выполняет системный вызов execve для изменения образа памяти и запуска новой программы. В Windows вызов всего одной функции CreateProcess управляет и созданием процесса, и запуском нужной в ней программы. После создания нового процесса, родительский и дочерний процессы имеют собственные различные адресные пространства. В тоже время, созданный процесс может использовать одинаковые ресурсы с родительским процессом, например, открытые файлы. Завершение процесса Основные события, приводящие к завершению процесса: ○ Обычный выход (преднамеренно) ○ Выход по ошибке (преднамеренно) ○ Выход по неисправимой ошибке (непреднамеренно) ○ Уничтожение другим процессом (непреднамеренно) В основном, процессы завершаются по мере выполнения своей работы. После окончания компиляции программы, компилятор выполняет системный запрос, чтобы сообщить операционной системе о завершении работы. В UNIX этот запрос - exit, а в Windows - ExitProcess. Так же, причиной завершения процесса может служить выполнение другим процессом системного запроса на уничтожение процесса. В UNIX такой системный запрос - kill, а в Windows - TerminateProcess. В обоих случаях “киллер” должен обладать соответствующими правами к убиваемому процессу. Иерархия процессов. В некоторых системах родительский и дочерний процессы остаются связанными между собой определенным образом. Дочерний процесс также может, в свою очередь, создавать процессы, формируя иерархию процессов. Следует отметить, что в отличии от животного мира у процесса может быть только один родитель и сколько угодно “детей”. В UNIX процесс, все его “дети” и дальнейшие потомки образуют группу процессов. Сигнал, посылаемый пользователем с клавиатуры, доставляется всем членам группы, взаимодействующим с клавиатурой в данный момент (обычно это все активные процессы, созданные в текущем окне). Каждый из процессов может перехватить сигнал, игнорировать его или выполнить другое действие, предусмотренное по умолчанию. Рассмотрим в качестве примера иерархии процессов инициализацию UNIX при запуске. В образе загрузке присутствует специальный процесс init. При запуске этот процесс считывает файл, в котором находится информация о количестве терминалов. Затем процесс разветвляется таким образом, чтобы каждому терминалу соответствовал один процесс. Процессы ждут, пока какой-нибудь пользователь не войдет в систему. Если пароль правильный, то процесс входа в систему запускает запускает оболочку для обработки команд пользователя, которые, в свою очередь могут запускать другие процессы. Таким образом, все процессы в системе принадлежат к единому дереву, начинающемуся с процесса init. Напротив, в Windows не существует понятия иерархии процессов и все процессы равноправны. Единственное, в чем проявляется что-то вроде иерархии процессов - создание процесса, в котором родительский процесс получает специальный маркер (так называемый дескриптор), позволяющий контролировать дочерний процесс. Но марке можно передавать другому процессу, нарушая иерархию. В UNIX это невозможно. Состояния процесса. Существуют три возможных состояния процесса: ○ Работающий (в этот конкретный момент использующий процессор) ○ Готовый к работе (процесс временно приостановлен, чтобы позволить выполниться другому процессу) ○ Заблокированный (процесс не может быть запущен прежде, чем произойдет некое внешнее событие) Как показано на рисунке, между тремя этими состояниями возможны четыре перехода. Переход 1 происходит тогда, когда процесс обнаруживает, что продолжение работы невозможно. Переходы 2 и 3 вызываются частью операционной системы, названной планировщиком процессов, так что сами процессы даже не знают о существовании этих переходов. Переход 2 происходит тогда, когда планировщик решил предоставить процессор другому процессу. Переход 3 происходит, когда все остальные процессы исчерпали свое процессорное время, и процессор возвращается к первому процессу. Переход 4 происходит с появлением внешнего события, ожидавшегося процессором (например, прибытие входных данных). Если в этот момент не запущен какой-либо другой процесс, то срабатывает переход 3. Иначе, процесс будет находиться в состоянии готовности еще некоторое время. Таблица процессов. Для реализации модели процесса операционная система содержит таблицу (массив структур), называемую таблицей процессов, с одним элементом для каждого процесса (эти элементы иногда называют блоками управления процессом) элемент таблицы содержит информацию о состоянии процесса, счетчике команд, указателе стека, распределении памяти, состоянии открытых файлов, об распределении и использовании ресурсов, а также всю остальную информацию, которую необходимо сохранять при переключении в состояние готовности или блокировки для последующего запуска - как если бы процесс не останавливался. Потоки. В настоящее время в большинстве ОС определены два типа единиц работы. Более крупная единица работы, обычно носящая название процесса, или задачи, требует для своего выполнения нескольких более мелких работ, для обозначения которых используют термины "поток", или "нить". Очевидно, что любая работа вычислительной системы заключается в выполнении некоторой программы. Поэтому и с процессом, и с потоком связывается определенный программный код, который для этих целей оформляется в виде исполняемого модуля. Чтобы этот программный код мог быть выполнен, его необходимо загрузить в оперативную память, возможно, выделить некоторое место на диске для хранения данных, предоставить доступ к устройствам ввода/вывода, например, последовательному порту. В ходе выполнения программе может также понадобиться доступ к ИР, например, файлам. И, конечно же, невозможно выполнение программы без предоставления ей процессорного времени, т.е. времени, в течение которого процессор выполняет коды данной программы. В системах, где существуют и процессы, и потоки, процесс рассматривается ОС как заявка на потребление всех видов ресурсов, кроме одного – процессорного времени. Этот последний важнейший ресурс распределяется ОС между другими единицами работы – потоками, которые и получили свое название благодаря тому, что они представляют собой последовательности (потоки выполнения) команд. В простейшем случае процесс состоит из одного потока, и именно таким образом трактовалось понятие "процесс" до середины 1980-х гг., и в таком же виде оно сохранилось в некоторых современных ОС. В системах этого вида понятие "поток" полностью поглощается понятием "процесс", т.е. остается только одна единица работы и потребления ресурсов – процесс. Мультипрограммирование осуществляется в таких ОС на уровне процессов. Потоки возникли в ОС как средство распараллеливания вычислений. Конечно, задача распараллеливания вычислений в рамках одного приложения может быть решена и традиционными способами. Для этих целей современные ОС предлагают механизм многопоточной обработки (multithreading). При этом вводится новая единица работы – поток выполнения, а понятие "процесс" в значительной степени меняет смысл. Понятию "поток" соответствует последовательный переход процессора от одной команды программы к другой. Операционная система распределяет процессорное время между потоками. Процессу ОС назначает адресное пространство и набор ресурсов, которые совместно используются всеми его потоками. В однопрограммных системах не возникает необходимости введения понятия, обозначающего единицу работы, так как там не существует проблемы разделения ресурсов. Создание потоков требует от ОС меньших накладных расходов, чем процессы. В отличие от процессов, которые принадлежат разным конкурирующим приложениям, все потоки одного процесса всегда принадлежат одному приложению, поэтому ОС изолирует потоки в гораздо меньшей степени, нежели процессы в традиционной мультипрограммной системе. Все потоки одного процесса используют общие файлы, таймеры, устройства, одну и ту же область оперативной памяти, одно и то же адресное пространство. Это означает, что они разделяют одни и те же глобальные переменные. Поскольку каждый поток может иметь доступ к любому виртуальному адресу процесса, один поток может использовать стек другого потока. Между потоками одного процесса нет полной защиты, потому что, во-первых, это невозможно, а во-вторых, не нужно. Чтобы организовать взаимодействие и обмен данными, потокам вовсе не требуется обращаться к ОС, им достаточно использовать общую память – один поток записывает данные, а другой читает их. С другой стороны, потоки разных процессов по-прежнему хорошо защищены друг от друга.