Мобильное программирование приложений реального времени в стандарте POSIX

       

Функции управления планированием


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

Стандарт POSIX-2001 предусматривает следующие функции управления планированием: sched_getscheduler() (опрос политики планирования процесса), sched_getparam() (опрос параметров планирования процесса), sched_setscheduler() (установка политики и параметров планирования процесса) и sched_setparam() (установка параметров планирования процесса) (см. листинг 6.1).

#include <sched.h>

int sched_getscheduler (pid_t pid);

int sched_getparam (pid_t pid, struct sched_param *param);

int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param);

int sched_setparam (pid_t pid, const struct sched_param *param);

Листинг 6.1. Описание функций управления планированием. (html, txt)

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

Функция sched_getparam() записывает параметры планирования заданного процесса по указателю param, в структуру типа sched_param; ее нормальный результат равен нулю. (Напомним, что, согласно стандарту POSIX-2001, у структуры типа sched_param только одно обязательное поле – приоритет sched_priority.)

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

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

Любопытно отметить, что стандарт POSIX-2001 не требует атомарности вызова sched_setscheduler() с точки зрения выполняющихся потоков управления. Хотя в итоге изменится все или ничего, эти изменения могут наблюдаться как поэтапные; соответственно они будут сказываться на поведении потоков.

Функция sched_setparam(), в отличие от sched_setscheduler(), изменяет только параметры планирования, но ее воздействие на заданный процесс стандартизовано детальнее.

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

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

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

Стандарт POSIX-2001 предоставляет средства для опроса характеристик политик планирования – минимального (sched_get_priority_min()) и максимального (sched_get_priority_max()) среди допустимых приоритетов, а также величины кванта выделяемого процессорного времени для политики циклического планирования (sched_rr_get_interval()) (см. листинг 6.2).

#include <sched.h>

int sched_get_priority_min (int policy);

int sched_get_priority_max (int policy);



int sched_rr_get_interval (pid_t pid, struct timespec *q_ptr);

Листинг 6.2. Описание функций опроса характеристик политик планирования. (html, txt)

Функция sched_rr_get_interval() записывает по указателю q_ptr в структуру типа timespec величину кванта процессорного времени, выделяемого заданному процессу, и возвращает нуль в качестве нормального результата.


Нормальными результатами функций sched_get_priority_min() и sched_get_priority_max(), разумеется, служат, соответственно, минимальный и максимальный приоритеты.

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

#include <sched.h> int sched_yield (void);

Листинг 6.3. Описание функции sched_yield(). (html, txt)

Следующая программа (см. листинг 6.4) иллюстрирует применение описанных функций. Возможные результаты ее выполнения для ОС Linux и операционной системы реального времени oc2000 показаны на листингах 6.5 и 6.6.

Листинг 6.4. Пример программы, использующей функции управления планированием. (html, txt)

Листинг 6.5. Возможные результаты выполнения программы, использующей функции управления планированием, в ОС Linux. (html, txt)

Листинг 6.6. Возможные результаты выполнения программы, использующей функции управления планированием, в операционной системе реального времени oc2000. (html, txt)

Проиллюстрируем теперь ситуацию с инверсией приоритетов (см. листинг 6.7).

Листинг 6.7. Пример программы, моделирующей ситуацию инверсии приоритетов. (html, txt)

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

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

Возможные результаты выполнения приведенной программы под управлением операционной системы реального времени oc2000 показаны на листинге 6.8.

Листинг 6.8. Возможные результаты выполнения программы, моделирующей ситуацию инверсии приоритетов, под управлением операционной системы реального времени oc2000. (html, txt)


Содержание раздела