Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
0041 Лекції_СРЧ.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
342.02 Кб
Скачать

Файлы и каталоги в qnx4

Файл — это набор байтов, имеющих общие атрибуты:

  • имя файла;

  • идентификатор владельца и идентификатор группы;

  • атрибуты доступа (для владельца, для членов группы и для остальных пользователей);

  • метки времени (время создания файла, время последней модификации файла, время последнего доступа к файлу, время последней записи в файл);

  • тип файла;

  • другие атрибуты.

Имя файла с добавлением списка разделенных символом "/" каталогов, содержащих файл, начиная с корневого каталога, называется полным или путевым именем файла.

(Например, /usr/photon/bin/slideviewer. Здесь файл с именем slideviewer имеет путь /usr/photon/bin).

QNX обеспечивает поддержку следующих типов файлов:

  • обычные (регулярные) файлы;

  • каталоги;

  • жесткие ссылки;

  • символические ссылки;

  • именованные программные каналы (FIFO);

  • блок-ориентированные специальные файлы;

  • байт-ориентированные специальные файлы;

  • "Именованные специальные устройства".

Обычные (регулярные) файлы

Обычные файлы это последовательность байт, не имеющих предопределенной структуры. За интерпретацию содержимого обычных файлов отвечают конкретные приложения. В отличие от операционных систем семейства Windows, QNX узнает исполняемые файлы не по расширению (вроде .ехе), а по специальному атрибуту.

Каталоги

Каталоги – это обычные файлы, имеющие определенную структуру. Эта структура представляет собой набор записей, которые называют элементами каталога.

Первый элементом каталога всегда содержит файл с именем ".". Этот элемент ссылается на свой собственный каталог, указывая на соответствующую запись в родительском каталоге.

Второй элемент каталога всегда содержит файл с именем "..". Этот элемент ссылается на родительский каталог, а точнее на его первый элемент.

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

Каждый элемент каталога связывает имя некоторого файла со служебной информацией о нем, включающей ссылку на место физического хранения данных. Структура содержимого элемента каталогаследующая:

  • 16 байт для имени файла;

  • размер файла;

  • информация о физическом размещении содержимого файла на диске (указатель на метаданные – номер inode);

  • метки времени;

  • атрибуты доступа;

  • счетчик ссылок на физические данные;

  • тип файла;

  • статус ("закрыт" или "открыт").

Если длина имени какого-нибудь файла превысит 16 символов, то в файле /.inodes будет создана запись для этого файла, в которую переместится вся информация о файле, кроме имени. В файловой записи каталога останутся имя файла (теперь оно может достигать 48 символов) и, ссылка на запись в /.inodes. При длине имени более 48 до 505 символов часть имени файла начиная с 49 символа ОС помещает в файл .longfiienames.

Размещение регулярных файлов и каталогов на диске.

В QNX регулярные файлы и файлы каталога хранятся как последовательность экстентов. Экстент - это непрерывная последовательность блоков на диске.

Файлы, которые состоят только из одного экстента, хранят информацию об экстенте (указатель inode на экстент) в элементе каталога. Если файл состоит более чем из одного экстента, информация о расположении экстентов хранится в одном или более связных блоках экстентов (связные - имеющие прямые/обратные указатели inode). Каждый блок экстентов может содержать информацию не более чем о 60 экстентах.

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

Для выделения новых экстентов Менеджер файловой системы использует метод "первого попадания". Специальная таблица в Менеджере файловой системы содержит сведения обо всех блоках, описанных в файле /.bitmap. Для каждого блока указывается размер соответствующего ему свободного экстента. Менеджер файловой системы выбирает из таблицы первый достаточно большой экстент.

Жесткие ссылки

Имя файла в каталоге жестко связано с метаданными (т.е. с содержимым, данными файла) через указатель inode, в то же время сами метаданные существуют независимо от того как их называют в файловой системе и не содержат ссылок на элемент каталога. Поэтому на одни и те же метаданные можно ссылаться из различных каталогов.

Если для одних и тех же физических данных существующего файла создается еще один элемент каталога, то эти дополнительные имена (т.е. элементы каталога) называют жесткими ссылками (или "жесткими связями").

Все жесткие ссылки абсолютно равноправны.

При создании жесткой ссылки, во-первых, информация о физическом размещении данных выносится в файл /.inodes, во-вторых, счетчик ссылок увеличивается на единицу. При удалении одной из жестких ссылок реально будет удален только соответствующий элемент каталога, а счетчик ссылок в inode-записи будет уменьшен на единицу. Созданная inode-запись сохраняется, пока существует файл, даже если счетчик стал равен единице и длина имени файла менее 16 символов. Как только счетчик достигнет значения "нуль", и inode-запись, и физические данные файла будут уничтожены (для уничтожения файла его статус файла должен иметь значение "закрыт").

Нельзя создавать жесткие связи для каталога. Однако каждый каталог имеет две жестко определенные связи:

  • . ("точка")

  • .. ("точка точка")

Имя файла "точка" соответствует текущему каталогу; "точка точка" соответствует каталогу, предшествующему текущему каталогу.

"Точка точка" для каталога "/" - это просто "/", - и подняться выше нельзч.

Символические ссылки

Символическая связь ("мягкая" ссылка) - это особый файл, который содержит в качестве данных имя пути. Когда символическая связь используется в запросе ввода/вывода - например, open(), - обозначение связи в имени пути заменяется ее "данными". Символическая связь является гибким средством для перенаправления пути и часто используется для создания множества путей к одному и тому же файлу. В отличие от жестких связей, символические связи могут выходить за пределы файловой системы, а также являться связями для каталогов.

Символическая ссылка это, по сути дела, текстовый файл, содержащий имя другого файла или каталога, к которому перенаправляются все запросы ввода/вывода.

Символическая ссылки, в отличие от жесткой, может указывать на файл или каталог, находящийся на другом физическом носителе (например, в другом разделе диска или на другом узле сети).

В следующем примере каталоги //1/usr/fred и //2/usr/barney являются связями на один и тот же каталог, хотя они находятся в различных файловых системах, и даже на различных узлах (смотри следующую диаграмму). Это не может быть сделано с использованием жестких связей:

//1/usr/fred --> //2/usr/barney

Заметьте, что символическая связь и адресуемый каталог не обязаны иметь одно и то же имя. В большинстве случаев символические связи используются для привязки одного каталога к другому. Однако они также могут быть использованы для файлов, как в этом примере:

//1/usr/eric/src/test.c --> //1/usr/src/game.c

Если вы хотите: Используйте утилиту: Создать символическую связь ln (с опцией -s) Удалить символическую связь* rm Узнать, является ли файл символической связью ls

* Помните, что удаление символической связи действует только на связь, а не на адресуемый объект

Так как создание «мягких» связей для каталогов создает опасность бесконечных циклов, число переходов по символиче­ским связям ограничено. (задается переменной SYMLOOP_MAX, определенным в заголовочном файле <limits .h>).

Именованные программные каналы (FIFO)

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

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

FIFO – это разновидность программных каналов, отличительной особенностями которых является то, что они являются именованными постоянными файлами и хранятся в каталогах файловой системы.

Блок-ориентированные специальные файлы

Блок-ориентированные специальные файлы ("блочные устройства") – это файлы, предназначенные для изоляции приложений от физических характеристик аппаратуры. Обмен данными с блочными файлами осуществляется блоками по несколько байт (например, при рабо­те с жестким диском размер блока обычно равен 512 байт). В QNX блок-ориентированные специальные файлы создаются не на диске, а в оперативной памяти при старте соответствующих драйверов.

Байт-ориентированные специальные файлы

Байт-ориентированные специальные файлы ("символьные устройства") — это файлы, аналогичные файлам «блочные устройства», с той разницей, что они обеспечивают интерфейс к аппаратуре, осуществляющей посимвольный ввод/вывод. (например, к таким, как последовательный порт, сетевая карта и т. п.)

Байт-ориентированные специальные файлы создаются драйверами при запуске.

"Named Special Device" — "именованные специальные устройства"

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

Обмен посредством этого типа файлов требует знания формата данных от всех участников обмена.

Лекция 4. Программы процессы и потогки в ОС РВ QNX 6

Обычно программой называют совокупность файлов, будь то набор обычных файлов, будь то набор исходных текстов, объектных файлов или собственно выполняемый файл.

Мы будем понимать под программой именно выполняемый файл.

Компилятор и стандартные библиотеки Си и С++ входят в комплект поставки операционной системы. Пути к стандартным библиотечным функциям настраиваются автоматически при установке операционной системы. Исходные тексты программ готовятся с использованием встроенного редактора vi, или штатного редактора графической среды Photon. Объектные и исполнимые файлы получают с использованием утилит gcc и (QCC). Параметры компиляции либо описываются с помощью файла makefile , либо указываются в командной строке компилятора. Для достаточно простых задач используют утилиту make .

При создании программ главный поток процесса, т.е. тот, с которого начинается выполнение процесса оформляется как функция main, а остальные потоки – как функции с параметром – указателем типа void и возвращаемым результатом – указателем типа void которые компонуются в единый исполнимый модуль. Он содержит коды как главного потока (функции main()) так и остальных потоков

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

Окружение (среда выполнения) программы вместе с ее выполняемым кодом получили название процесса.

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

Непрерывная последовательность команд, которые выполняются непосредственно процессором (CPU), называется потоком. Таким образом, запущенная программа становится потоком в составе процесса.

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

QNX 6 является многопроцессной многопотоковой операционной системой. Это означает, что параллельно на исполнении могут находиться несколько программ, т.е. существовать несколько процессов каждый из которых может включать несколько потоков.

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

Адресные пространства процессов устанавливаются и поддерживаются модулем администратора процессов QNX6. При запуске процесса администратор процессов распределяет ему некоторый объем памяти и активирует его потоки. Отведенная данному процессу память помечается как принадлежащая ему.

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

Таким образом, переключение между потоками в одном процессе происходит быстрее, но сбои в каком либо потоке процесса могут привести к нарушению выполнения других потоков этого процесса.

Жизненный цикл процесса включает четыре этапа.

1. Создание.

2. Загрузка кода и данных процесса в ОЗУ.

3. Выполнение потоков

4. Завершение.

Процесс может быть создан только другим (родительским) процессом. При этом администратор процессов создает у себя необходимые структуры данных.

Завершение процесса протекает в две стадии. Первую стадию выполняет поток завершитель (termination thread) администратора процессов. При этом происходит освобождение ресурсов, связанных с процессом (страницы ОЗУ, открытые файловые дескрипторы и т. п). Поток завершитель выполняется с идентификатором уничтожаемого процесса.

Вторая стадия завершения процесса протекает внутри администратора процессов, при этом код возврата завершаемого процесса передается процессу-родителю. Возможны следующие варианты:

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

  2. процесс-родитель отказался от получения кода завершения дочернего процесса, т. е. завершающийся процесс имел флаг SPAWN_NOZOMBIE. В этом случае дочерний процесс будет немедленно завершен;

  3. процесс-родитель не отказывался от получения кода возврата дочернего процесса, но и не вызвал функцию получения этого кода. В этом случае дочерний процесс блокируется до тех пор, пока родитель не прочтет код завершения, т. е. завершающийся процесс становится DEAD-блокированным или "зомби".

При создании процесс (главный поток) имеет ряд атрибутов:

  • идентификатор процесса (process ID – pid);

  • идентификатор родительского процесса (parent process ID – ppid);

  • реальные идентификаторы владельца и группы (uid и gid);

  • эффективные идентификаторы владельца и группы (euid и egid);

  • текущий рабочий каталог;

  • управляющий терминал;

  • маска создания файлов (umask);

  • номер приоритета;

  • дисциплина диспетчеризации.

При создании потоков внутри процесса они наследуют основные атрибуты процесса. Некоторые атрибуты, такие, как, например, номер приоритета, дисциплина диспетчеризации для потока могут устанавливаться индивидуально.

Запуск процесса.

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

Для запуска процесса из командного интерпретатора необходимо ввести командную строку:

$ program1

Это предписывает командному интерпретатору запустить программу program1 и ждать завершения ее работы.

Если набрать:

$ program2 &

то это предписывает командному интерпретатору запустить программу program2 без ожидания ее завершения. В таком случае говорят, что программа program2 работает в фоновом режиме и из командной строки можно запустить другой процесс, например, programs.

Если необходимо при запуске потока скорректировать приоритет программы до ее запуска, например увеличить на 5 , необходимо использовать команду nice:

$ nice 5 programs

Утилита on позволяет запустить процесс с заданным приоритетом и дисциплиной диспечеризации.

Запуск процесса из потока может быть осуществлен с использованием одной из следующих функций:

system();

семейство функций ехес();

семейство функций spawn();

fork();

vfork().

Какую из этих функций применять, зависит от двух требований: переносимости и функциональности.

Обычно при всех запросах на создание нового процесса происходит следующее.

Поток в первоначальном процессе вызывает одну из вышеприведенных функций. В конечном итоге, функция заставит администратор процессов создать адресное пространство для нового процесса. Затем ядро выполнит запуск системного потока в новом процессе. Этот поток выполнит несколько инструкций и вызовет функцию main().

Функция system() получает на вход одну командную строку, такую же, которую набирают в ответ на запрос командного интерпретатора, и выполняет ее. Фактически, для обработки команды, функция system() запускает копию командного интерпретатора.

systemprogram)

Семейство функций ехес() подменяет текущий процесс другим. Когда процесс вызывает функцию семейства ехес(), этот процесс прекращает выполнение текущей программы (т.е всех потоков, входящих в процесс) и начинает выполнять другую программу. Идентификатор процесса (PID) при этом не меняется, просто процесс преобразуется в другую программу.

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

В качестве параметров функциям семейств ехес() и spawn() передается полное имя вызываемой программы и, при необходимости, опции ее выполнения (аргументы функции main()).

Функция fork() создает новый процесс, копируя текущий процесс. У созданного процесса как код, так и данные полностью совпадают с кодом и данными родительского процесса. Дочерний процесс, будет стартовать с команды, следующей непосредственно за вызовом функции fork(). Однако между этими двумя процессами будет иметь место ряд различий, в частности этих двух процессов будут отличаться pid и ppid , а ppid у дочернего процесса будет равен pid процесса-родителя, функции fork() в родительский процесс вернет pid процесса-потомка, а в процесс потомок 0.

Т.е. фрагмент программы:

int child_pid

printf («PID родителя равен %d\n», getpid());

if (child_pid = fork()) {

printf («Это родитель, PID сына %d\n»,

child_pid);

}

else {

printf («Это сын, PID %d\n», getpid ())

выведет на экран примерно следующее:

PID родителя равен 4496

Это родитель, PID сына 8197

Это сын, PID 8197

Последовательный вызов функций fork() и ехес() в UNIX является основным механизмом создания нового процесса.

Применение функции vfork() по сравнению с обычной fork() позволяет существенно сэкономить на ресурсах, поскольку она делает разделяемым адресное пространство родителя.

Функция vfork() создает «сына», но затем приостанавливает родительский поток до тех пор, пока «сын» не вызовет функцию ехес() или не завершится (с помощью, например, функции exit()).

Новый процесс наследует дисциплину диспетчеризацию у процесса – родителя.

Изменить (установить) приоритет потока можно функциями setprio(), прочитать – getprio().

Запуск потока.

Любой поток может создать другой поток в том же самом процессе; на это не налагается никаких ограничений (за исключением объема памяти. Наиболее общий путь реализации этого – использование вызова функций POSIX pthread_create():

#include <pthread.h>

int

pthread_create (pthread_t *thread,

const pthread_attr_t *attr,

void *(*start_routine) (void *),

void *arg);

Функция pthread_create() имеет четыре аргумента :

thread указатель на структуру pthread_t, где хранится идентификатор потока;

attr атрибутная запись;

start_routine подпрограмма, с которой начинается поток;

arg параметр, который передается подпрограмме start_routine

Указатель thread и атрибутная запись (attr) — необязательные элементы, и можно передавать вместо них передавать NULL.

Параметр thread может использоваться для хранения идентификатора вновь создаваемого потока:

pthread_t tid;

pthread_create (&tid, .. .

printf («Новый поток имеет идентификатор %d\n», tid);

Новый поток начинает выполнение с функции start_routine, с параметром arg.

При создании потока он устанавливает некоторые свои атрибуты из структуры с типом данных pthread_attr_t потока-родителя и создает структуру данных pthread_attr_t , копируя туда данные из структуры типа pthread_attr_t потока-родителя.

Структура типа pthread_attr_t следующая:

typedef struct {

int flags;

size_t stacksize;

void *stackaddr;

void (*exitfunc)(void *status);

int policy;

struct sched_param param;

unsigned guardsize;

} pthread_attr_t;

В основном эти поля используются как:

flags Неисчисляемые (булевы) характеристики потока — например, создается поток как «обособленный» или «синхронизирующий».

stacksize, stackaddr и guardsize Параметры стека

exitfunc – Функция, выполняемая перед завершением потока,

policy и рarат Параметры диспетчеризации. В версии QNX6.2 структура param содержит единственный элемент sched_prioriti

Для управления атрибутами потока необходимо прежде инициализировать структуру pthread_attr_t . Для этого предназначена функция pthread_attr_init() (для деинициализации структуры предназначена функция pthread_attr_destroy( ), однако она практически не используется.

Примечание: ptread_attr_t attr;

ptread_attr_init (&attr).

Функцию pthread_attr_init() для инициализации атрибутной записи необходимо вызвать до момента ее использования, задействовать ее с помощью соответствующей функции (функций) pthread_attr_set*() и только затем вызвать функцию pthread_create() для создания потока. Изменение атрибутной записи после того, как поток уже создан, не будет иметь никакого действия.

Прочесть элементы атрибутной записи можно с использованием соответствующей функции (функций) pthread_attr_get*()

В зависимости от того, какой атрибут необходимо изменить/прочесть, необходимо подставлять в имя функции pthread_attr_set*() / pthread_attr_get*() соответствующее значения:

Флаги (булевы характеристики) устанавливаются следующими функциями:

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

pthread_attr_setdetachstate(&attr, PTHREAD_CRATE_JOINABLE) – синхронизирующий

pthread_attr_setdetachstate(&attr, PTHREAD_CRATE_DETACHED) – не синхронизирующий

pthread_attr_setdetachstate(&attr, PTHREAD_INHERIT_SHED) – наследует атрибут потока-родителя (по умолчанию)

pthread_attr_setinheritsched() – устанавливает способ задания параметров диспетчеризации, т.е. создаваемый поток наследует параметры диспетчеризации потока-родителя (по умолчанию либо константой PTHREAD_INHERIT_SHED) или параметры диспетчеризации устанавливаются (константа PTHREAD_EXPLICIT_SHED) функциями pthread_attr_setschedparam( ) – уровень приоритета и pthread_attr_setschedpolicy ( ) – дисциплина диспетчеризации: карусельная (константой SCHED_RR), FIFO (константой SCHED_ FIFO) или другая (константой SCHED_OTHER). В версии QNX/Neutrino 6.2 параметр SCHED_OTHER интерпретируется как SCHED_RR (карусельная диспетчеризация), а в версии 6.3. – как спорадическая.

В версии 6.3. для установки спорадической диспетчеризации используется также константа SCHED_SPORADIC

pthread_attr_setscope() – устанавливает имеет ли поток масштаб процесса или системы. Масштаб системы означает, что за обладание ресурсами все потоки в системе конкурируют друг с другом; масштаб процесса же означает, что потоки конкурируют за процессор только в пределах «своего» процесса, а диспетчеризацию процессов выполняет ядро. QNX/Neutrino поддерживает для потоков только масштаб системы, и эта функция практически не используется.

Для установки параметров стека служат функции

pthread_attr_setguardsize(); pthread_attr_setstackaddr(); pthread_attr_setstacksize()

Большинство функций сгруппированы по парам «get» — «set», т. е. в каждой паре есть функция как получения параметров (get), так и их установки (set) – за исключением функций pthread_attr_init() и pthread_attr_destroy().

Лекция 5. Приоритеты дисциплина диспечеризации потоков в ОС РВ QNX 6

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

Если эти потоки имеют различные приоритеты, то ядро отдает процессор потоку с высшим приоритетом. Приоритеты в QNX/ Neutrino пронумерованы от единицы (самый низкий) и далее, с единичным дискретом (до 63 в QNX 6.2 до 255 в QNX 6.3). Нулевой приоритет использовать нельзя — он зарезервирован для «холостого» (idle) потока.

Минимальное или максимальное значение приоритета в системе можно узнать с помощью функций sched_get_priority_min() и sched_get_priority_max(), описаных в <sched.h>.

Если другой поток с более высоким приоритетом вдруг становится готов к выполнению, ядро немедленно переключит контекст на поток с более высоким приоритетом. Это называется вытеснением – поток с высшим приоритетом вытесняет поток с низшим приоритетом. Ситуацию, когда поток с высшим приоритетом заканчивает свою работу, и ядро переключает контекст обратно на поток с низшим приоритетом, который выполнялся ранее, называют возобновлением – ядро возобновляет работу предыдущего потока.

Если два потока готовы к выполнению и имеют один и тот же приоритет (максимальный из всех потоков готовых к выполнению), то решение о переключении контекста в такой ситуации принимается ядром в зависимости от дисциплины диспечеризации.

Ядро QNX6.2 поддерживает две дисциплины диспетчеризации: карусельную, она же RR (Round Robin), и FIFO (First InFirst Out). Ядро QNX6.3 дополнительно поддерживает спорадическую диспетчеризацию (SPORADIC).

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

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

Выражение «добровольно уступить процессор» может означать одну из двух возможных ситуаций. Если поток переходит в режим ожидания, например, блокируется на семафоре, тогда может выполняться поток с более низким приоритетом (как описано выше). Существует также специальная функция sched_yield(), по которой процессор передается только другому потоку с тем же самым приоритетом. Если поток вызывает функцию sched_yield(), но никакой другой поток с таким же самым приоритетом не готов к выполнению, первоначальный поток продолжает работу.

Дисциплина RR (карусельная диспетчеризация) аналогична дисциплине диспетчеризации FIFO, за исключением того, что поток будет работать только в течение предопределенного кванта времени (который фиксирован и не может быть изменен). Величину кванта времени можно узнать, используя функцию sched_rr_get_interval().

Когда ядро запускает на обработку поток с дисциплиной диспетчеризации RR, оно фиксирует время. Если поток не блокируется в течение выделенного ему кванта времени, квант времени истечет. Тогда ядро проверяет наличие другого готового к выполнению потока с тем же самым приоритетом. Если такой поток обнаруживается, то ядро активирует его. Если такого потока нет, то ядро снова ставит на выполнение предыдущий поток (то есть ядро выделяет потоку для работы еще один квант времени).

Дисциплина спорадической диспетчеризации (SPORADIC) предназначена для потоков, обрабатывающих события, срок поступления которых не может наступать ранее некоторого времени после их предыдущего поступления.

При спорадической дисциплине потоку задается несколько параметров:

  • Нормальный приоритет или приоритет переднего плана (N) – приоритет потока, при котором планируется основная, критичная к времени, обработка события;

  • Нижний или фоновый приоритет (L) – приоритет потока, при котором планируется некритичная к времени обработка события;

  • Начальный бюджет потока (С) – количество времени, которое поток может выполняться с нормальным приоритетом (N), перед тем, как получить пониженный приоритет (L).

  • Период пополнения (T) – период времени, в течении которого поток может расходовать свой бюджет выполнения.

  • Максимальное число текущих пополнений – ограничение на количество последовательных пополнений ненулевого текущего бюджета выполнения.

Алгоритм спорадического планирования устанавливает начальный бюджет выполнения потока (С) с нормальным приоритетом (N), который расходуется потоком и пополняется с периодичностью, определенной периодом пополнения.

После полного расходования бюджет выполнения и до его пополнения поток выполняется с фоновым приоритетом (L).

Сводка правил диспетчеризации (для одиночного процессора) и в порядке важности имеет следующий вид:

  • только один поток может выполняться в данный момент времени;

  • всегда должен выполняться поток с наивысшим приоритетом, который не блокирован;

  • поток должен работать до тех пор, пока он не блокируется или не завершается;

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