Взаимодействие процессов в ОС Linux

Основными активными сущностями в Линукс являются процессы. По определению эти процессы являются классическими последовательностями процессов. Каждый поток изначально получает один поток управления (имеет один счётчик команд, который отслеживает следующую исполняеую команду). Также в Линукс процессу позволяется создавать дополнительные потоки. ОС Линукс представляет собой многозадачную систему, следовательно несколько независимых процессов могут работать одновременно. Для создания процессов в ОС Линукс используется системный вызов fork. При этом создаются точные копии исходного процесса(родительский процесс) дочерний процесс. У каждого процесса есть свои области памяти. Открытые файлы используются обеими процессами совместно; изменения произведённые с этим файлом будут видны каждому из процессов. У каждого процесса есть свой идентификатор (PID - Для дочернего он равен "0", для родительского отличен от "0").

2) Взаимодействие между процессами.

Взаимодействие между процессами ОС Линукс осуществляется с помощью двух механизмов:

- трубы(pipes) - канал между двумя процессами, в который один процесс может писать поток байтов, а другой считывать.

- сигналы(signals) - в данном случае взаимодействие происходит посредством программных прерываний; процесс может посылать сигналы только своей группе процессов (родитель, братья, сёстры и т.д.)

Реализация потоков в ОС Linux.

Исторически процессы были контейнерами ресурсов, а потоки - единицами исполнения. Процесс содержал один или несколько потоков, которые совместно использовали адресное пространство, открытые файлы, обработчики сигналов и все остальное.

В 2000 году в Линукс был введён новый системный вызов clone, который размыл различия между процессами и потоками. Ни в одной другой системе Unix вызова clone нет. Вызов clone создаёт новый поток либо в текущем процессе, либо в новом процессе. В первом случае, новый поток совместно использует совместно с уже существующими единое адресное пространство. Во втором случае, поток получает копию адресного пространства, которое становится недоступным для старых потоков (те, от которых он произошёл). Для сохранения совместимости с другими системами Линукс различает PID и идентификаторы задач (TID - Task IDentifer); оба эти поля хранятся с структуре задач. Когда вызов clone используется для создания нового процесса, PID устанавливается в новое значение, в противном случае задача получает новый TID, но наследует PID. Таким образом все потоки процесса получат тот же самый PID, что и первый поток процесса.

Планирование в ОС Linux.

Операционная система linux алгоритмом планирования различает 3 класса потоков (планирование linux происходит только на основе потоков, а не процессов) :

1. потоки реального времени, обслуживаемые по алгоритму fifo. данные потоки имеют наивысший приоритет и могут вытесняться только потоками того же типа.

2. потоки реального времени, обслуживаемые в порядке циклической очереди. данный тип потоков подобен предыдущему с тем отличием, что он имеет квант времени, т.е. данные потоки могут вытесняться по таймеру.

3. потоки разделения времени.

потоки реального времени имеют приоритеты 1 - 99, остальые - 100-139.

остальные потоки планируются в соответствии с приоритетами и алгоритмом циклической очереди.

Планировщик linux использует ключевую структуру данных, которая называется "очередь исполнения" (runqueue). Эта очередь связана с процессором и поддерживает 2 массива: active & expired. Каждый из этих массивов состоит из заголовков 140 списков.

Заголовок списка указывает на дважды связный список потоков данного приоритета. Планировщик выбирает задачу из активного массива с самым высоким приоритетом. Если квант времени этой задачи истек, то она переносится в список закончивших функционирование.

Если задача блокируется до истечения её кванта времени, то после события она помещается обратно в исходный активный массив, а её квант времени уменьшается на количество уже использованного времени процессора. Когда ни в одном из активных массивов больше нет задач, то планировщик меняет указатели для активного массива и массива задач, закончивших функционирование.

Разным уровням приоритетов, присваивается различный квант времени: чем больше приоритет, тем больший квант времени получает данный поток для приоритета 100 - 800млс, для приоритета 139 выделяется 5млс.

Приимущества данного подхода:

а) данный способ планирования гарантирует, что потоки с более низким приоритетом будут выполнены;

б) если, например, потоку необходимо считывание с диска, то, после предоставления такой возможности, ему дается право на быстрое выполнение.

По-скольку система linux является системой разделения времени, то невозможно предугадать, каким будет выполняться следующий процесс. В связи с этим в системе linux используются идея статического и динамического приоритетов.

Статический приоритет является постоянным для данной задачи и назначается по умолчанию в начале работы. Динамический приоритет назначается и изменяется во время работы в соответствии с политикой планирования.

Загрузка в ОС Linux

Точные детали процесса загрузки варьируется от системы к системе, однако общая схема этапов сохраняется. При включении компьютера начинается работа bios, которая производит тестирование при включении, а также начальное обнаружение устройств и их инициализацию. Затем, в память считывается и исполняется первый сектор загрузочного диска. Этот сектор содержит небольшую программу, считывающую автономную программу с загрузочного устройства (boot). Программа сначала копирует сама себя в старшие адреса памяти. после этого она считывает корневой каталог из загрузочного устройства. для этого она должна понимать формат файловой системы (существую загрузчики, которым не обязательна эта инфомарция). После этого программа boot считывает ядро операционной системы и передает ему управление. На этом этапе команда boot завершает свою работу.

Начальный код ядра написан на ассемблере. И является машинно-зависимым. Данный код выполняет следующие действия:

а) настраивает стэк ядра;

б) определяет тип центрального процессора;

в) вычисляет количество имеющейся оперативной памяти;

г) инициализирует прерывания;

д) разрешает работу блока управления памятью;

е) вызывает процедуру main. (написана на языке C).

Процедура main проделывает работу по инициализации остальной части операционной системы. В первую очередь выделяется память под буфер сообщений. В данный буфер записываются сообщения о ходе инициализации системы. Далее выделяется память для структур данных ядра. Большенство структур имеет фиксированный размер. Однако существуют такие, которые зависят от размера оперативной памяти (кэш страниц,таблица страниц). Далее операционная система начинает определение конфигурации компьютера. Для этого OS считывает файлы конфигурации, в которых сообщаются возможные устройства ввода\вывода, и проверяет, какие из них присутствуют на самом деле. Если устройство присутствует, оно добавляется в таблицу подключенных устройств. Иначе, устройство игнорируется.

После завершения конфигурации всего аппаратного обеспечения нужно настроить стек и загрузить процесс 0 (с самым высоким приоритетов). Процесс - продолжает инициализацию:

а) программирование таймера;

б) монтирование корневой файловой системы;

в) создание процесса 1 (init);

г) создание процесса 2 (page deamon).

Процесс init проверяет свои флаги, в зависимости от которых он запускает систему в однопользовательском или многопользовательском режиме.

Однопользовательский режим - в этом случае init создает процесс исполняющий оболочку и ждет, когда тот завершит свою работу.

Многопользовательский режим - в этом случае init создает процесс rc, который проверяет противоречивость файловой системы. Далее считывается файл ttys, в котором перечисляются терминалы и некоторые их свойства. для каждого из разрешенных терминалов он создает копию самого себя и запускает программу getty. Эта программа устанавливает для каждой линии скорость и прочие свойства, а также выводит сообщение для приглашения в систему (login:). Далее она считывает данные логина с клавиатуры, запускает программу login и завершает свою работу. Login запращивает у пользователя пароль, сравнивает с зашифрованным паролем. Если пароль верен, то логин запускает оболочку, если нет, то процесс запроса повторяется.