Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

GRID_УП

.pdf
Скачиваний:
75
Добавлен:
16.03.2016
Размер:
1.78 Mб
Скачать

151

6 МИКРОЯДРО ОС QNX NEUTRINO

6.1 Введение

Микроядро ОС QNX Neutrino реализует основные функции стандартов POSIX, используемые во встраиваемых системах реального времени, а также базовые службы обмена сообщениями. Те функции, которые не реализованы в микроядре, выполняются дополнительными процессами или разделяемыми библиотеками.

На самых нижних уровнях микроядра расположено всего несколько базовых объектов, а также четко отрегулированные процедуры для управления ими. Это является основой, на которой строится ОС QNX (рис. 6.1).

Интерфейс

Микроядро

Объекты

Поток

 

Соединение

Планирование

 

 

Синхронизация

 

Поток

 

Диспетчер

 

 

Сигнал

 

сообщения

 

 

Сообщение

 

 

Канал

 

Таймер

 

Вектор

 

 

Таймер

 

 

Часы

 

Импульс

 

 

Прерывания

 

Канал

Рис. 6.1 — Микроядро ОС QNX Neutrino

152

ВОС QNX Neutrino большинство служб по обеспечению работы в реальном времени и по планированию потоков реализовано прямо в микроядре. Эти службы могут работать без использования дополнительных модулей.

Вмикроядре ОС QNX существуют системные вызовы (kernel calls), которые служат для управления следующими объектами:

потоками;

сообщениями;

сигналами;

часами;

таймерами;

обработчиками прерываний;

семафорами;

блокировками взаимного исключения, мьютексами;

условными переменными;

барьерами.

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

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

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

153

На рис. 6.2 показан механизм вытеснения в ядре для процессоров с архитектурой Intel x86 без поддержки SMP. Запрет прерываний или отсутствие вытеснения происходит только на короткие периоды времени (как правило, эти периоды не превышают порядка сотен наносекунд).

SYSCALL

Вход

Микро-

 

 

 

секунды

 

 

 

 

Операции ядра, в том числе передача сообщений

От микросекунд до миллисекунд

 

Завершение

Микро-

 

 

секунды

 

 

Микро-

SYSEXIT

Выход

 

 

секунды

 

 

 

Прерывания

запрещены

Прерывания разрешены, полное вытеснение

Прерывания разрешены, вытеснения нет

Прерывания

запрещены

Рис. 6.2 — Механизм вытеснения в ОС QNX

154

6.2 Потоки и процессы

6.2.1Вызовы по управлению потоками

Вядре ОС QNX минимальной планируемой и выполняемой единицей является поток. Процесс можно рассматривать как объект, который содержит в себе эти потоки и определяет для их выполнения свое адресное пространство.

Вмикроядре ОС QNX реализован ряд вызовов по управлению потоками POSIX и соответствующие им вызовы микроядра

(табл. 6.1).

Таблица 6.1 — Вызовы по управлению потоками POSIX и соответствующие вызовы микроядра [9]

POSIX-вызов

Вызов микроядра

Описание

pthread_create()

ThreadCreate()

Создать поток

pthread_exit()

ThreadDestroy()

Уничтожитьпоток

pthread_detach()

ThreadDetach()

Отсоединить

 

 

поток, чтобы не

 

 

ждать его за-

 

 

вершения

pthread_join()

ThreadJoin()

Присоединить

 

 

поток и ждать

 

 

его кода завер-

 

 

шения

pthread_cancel()

ThreadCancel()

Завершить поток

 

 

вследующей

 

 

точке завершения

отсутствует

ThreadCtl()

Изменить харак-

 

 

теристики пото-

 

 

ка

pthread_mutex_init()

SyncTypeCreate()

Создать мьютекс

pthread_mutex_destroy()

SyncDestroy()

Уничтожить

 

 

мьютекс

pthread_mutex_lock()

SyncMutexLock()

Блокировать

 

 

мьютекс

pthread_mutex_trylock()

SyncMutexLock()

Условно блоки-

 

 

ровать мьютекс

 

155

 

Продолжение табл. 6.1

 

Описание

POSIX-вызов

Вызов микроядра

pthread_mutex_unlock()

SyncMutexUnLock()

Снять блокиров-

 

 

ку мьютекса

pthread_cond_init()

SyncTypeCreate()

Создать услов-

 

 

ную переменную

pthread_cond_destroy()

SyncDestroy()

Уничтожить ус-

 

 

ловную пере-

 

 

менную

pthread_cond_wait()

SyncCondvarWait()

Ожидать услов-

 

 

ную переменную

pthread_cond_signal()

SyncCondvarSignal()

Разблокировать

 

 

один из потоков,

 

 

блокированных

 

 

на условной пе-

 

 

ременной

pthread_cond_broadcast()

SyncCondvarSignal()

Разблокировать

 

 

все потоки, бло-

 

 

кированные на

 

 

условной пере-

 

 

менной

pthread_getschedparam()

SchedGet()

Получить пара-

 

 

метры планиро-

 

 

вания и дисцип-

 

 

лину потока

pthread_setschedparam()

SchedSet()

Установить па-

 

 

раметры плани-

 

 

рования и дис-

 

 

циплину потока

pthread_sigmask()

SignalProcMask()

Проверить и вы-

 

 

вести маску сиг-

 

 

налов потока

pthread_kill()

SignalKill()

Отправить сиг-

 

 

нал потоку

sem_post()

SyncSemPost()

Увеличить зна-

 

 

чение счетчика

 

 

на семафоре

sem_wait()

SynSemWait()

Уменьшить зна-

 

 

чение счетчика

 

 

на семафоре

 

 

 

156

 

 

 

 

Окончание табл. 6.1

 

 

 

 

Описание

 

POSIX-вызов

 

Вызов микроядра

 

 

pthread_barrierattr_getpshared()

 

Получить значение атрибута

 

 

 

 

 

совместного использования для

 

 

 

 

 

заданного барьера

 

 

pthread_barrierattr_ destroy()

 

 

Уничтожить атрибутную запись

 

 

 

 

 

барьера

 

 

pthread_barrierattr_iпit()

 

 

Инициализировать атрибуты

 

 

 

 

 

объекта

 

 

pthread_barrierattr_ setpshared()

 

Установить значение атрибута

 

 

 

 

 

совместного использования для

 

 

 

 

 

заданного барьера

 

 

pthread_barrier_destroy()

 

 

Уничтожить барьер

 

pthread_ barrier_iпit()

 

 

Инициализировать барьер

 

pthread_barrier_wait()

 

 

Синхронизировать потоки на

 

 

 

 

 

барьере

 

 

pthread_sleepon_lock()

 

 

Блокировать поток с использо-

 

 

 

 

 

ванием ждущей блокировки

 

pthread_rwlock_rdlock()

 

 

Блокировка потока по чте-

 

 

 

 

 

нию/записи

 

 

pthread_rwlock_wrlock()

 

 

Блокировка потока по записи

 

pthread_rwlock_unlock()

 

 

Снятие блокировки по чтению

 

pthread_rwlock_tryrdlock()

 

 

Тестирование блокировки по

 

 

 

 

 

чтению/записи

 

 

pthread_rwlock_trywrlock()

 

 

Тестирование блокировки по

 

 

 

 

 

записи

 

 

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

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

уникальным значением данных для каждого потока.

157

6.2.2 Состояния потока

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

Завершение потока включает в себя остановку потока и освобождение ресурсов потока.

Поток ОС QNX может находиться в одном из следующих состояний [9]:

CONDVAR — поток блокирован на условной переменной (например, при вызове функции pthread_cond_var_wait());

DEAD — поток завершен и ожидает завершения другого

потока;

INTERRUPT — поток блокирован и ожидает прерывания (при вызове функции InterruptWait());

JOIN — поток блокирован и ожидает завершения другого потока (например, при вызове функции pthread_join());

MUTEX — поток блокирован блокировкой взаимного исключения (например, при вызове функции pthread_mutex_

lock());

NANOSLEEP — поток находится в режиме ожидания в течение короткого периода времени (например, при вызове функции nanosleep());

NET_REPLY — поток ожидает ответа на сообщение другого узла сети (поток вызвал функцию MsgReply);

NET_SEND — поток ожидает получение импульса или сигнала от другого узла сети (поток вызвал функцию MsgSend-

Pulse(), MsgDeliverEvent или SignalKill());

READY — поток ожидает выполнения, пока процессор занят выполнением другого потока равного или более высокого приоритета;

RECEIVE — поток блокирован на операции получения сообщения (поток вызвал функцию MsgReceive);

158

REPLY — поток блокирован при ответе на сообщение (поток вызвал функцию MsgReply);

RUNNING — поток выполняется процессором;

SEM — поток ожидает освобождения семафора (поток вызвал функцию SyncSemWait());

SEND — поток блокируется при отправке сообщения (поток вызвал функцию MsgSend);

SIGSUSPEND — поток блокирован и ожидает сигнала (поток вызвал функцию sigsuspend());

SIGWAITINFO — поток блокирован и ожидает сигнала (поток вызвал функцию sigwaitinfo());

STACK — поток ожидает выделения виртуального адресного пространства для своего стека (родительский поток вы-

зывает функцию ThreadCreate());

STOPPED — поток блокирован и ожидает сигнала

SIGCOUNT;

WAITCTX — поток ожидает доступности нецелочисленного контекста;

WAITPAGE — поток ожидает выделения физической памяти для виртуального адреса;

WAITTHREAD — поток ожидает завершения создания дочернего потока (поток вызвал функцию ThreadCreate()).

6.2.3Планирование потоков

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

Как правило, выполнение приостановленного потока через некоторое время возобновляется. При этом планировщик (sсllеdulег) выполняет переключение контекстов с одного потока на другой всякий раз, когда активный поток [9]:

159

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

ит.д.). Блокированный поток удаляется из очереди готовности, после чего запускается поток с наивысшим приоритетом. Когда блокированный поток разблокируется, он помещается в конец очереди готовности на соответствующий приоритетный уровень;

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

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

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

Всего в ОС QNX Neutrino 6.3 поддерживается до 256 уровней приоритетов. Приоритет выполнения каждого непривилегированного потока может изменяться в пределах от 1 до 63 (наивысший приоритет), независимо от его дисциплины планирования. Только привилегированные (гoot) потоки могут иметь приоритет выше 63. Специальный поток с именем idle в администраторе процессов имеет приоритет 0 и всегда готов к выполнению. По умолчанию поток наследует приоритет своего родительского потока [9].

Команда procnto позволяет изменить диапазон допустимых приоритетов для непривилегированного процесса:

procnto -р приоритет

160

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

Потоки, находящиеся в очереди, упорядочиваются по приоритету. В действительности, очередь готовых потоков состоит из 256 отдельных очередей по одной на каждый приоритет. Потоки выстраиваются в очереди по порядку поступления (FIFO) и в соответствии с их приоритетом. Для выполнения выбирается первый поток с наивысшим приоритетом [9].

Для работы в ОС QNX Neutrino 6.3 используются следующие алгоритмы планирования:

FIFO-планирование (см. п. 3.1.2);

циклическое планирование (Round robin, см. п. 3.1.2);

спорадическое планирование.

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

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

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

Как и в FIFО-планировании, поток, для которого применяется спорадическое планирование, выполняется до тех пор, пока он не блокируется или прерывается потоком с более высоким приоритетом. Кроме того, так же как и в адаптивном планировании, поток, для которого применяется спорадическое планирование, получает пониженный приоритет. Однако спорадическое планирование дает значительно более точное управление потоком [9].

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]