Available Languages?:

TNKernel : Мютексы

Введение

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

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

Часто возникает вопрос - а зачем вообще нужно блокировать ресурсы? Все дело в принципе работы вытесняющих RTOS - задача может быть прервана (вытеснена) в любой момент времени. Если в этот момент она использует некий системный ресурс (например, UART), а задача, которая вытеснила текущую так же начнет с ним работать - возникнет закономерный конфликт.

Инверсия приоритетов

С блокировкой ресурсов тесно связано понятие инверсии приоритетов:

 Инверсия приоритетов

Допустим в системе существуют две задачи с низким (А) и высоким (Б) приоритетом. В момент времени T1 задача (А) блокирует ресурс и начинает его обслуживать. В момент времени T2 задача (Б) вытесняет низкоприоритетную задачу (А) и пытается завладеть ресурсом в момент времени T3. Но так как ресурс заблокирован, задача (Б) переводится в ожидание, а задача (А) продолжает выполнение. В момент времени Т4 задача (А) завершает обслуживание ресурса и разблокирует его. Так как ресурс ожидает задача (Б), она тут же начинает выполнение.

Временной промежуток (T4-T3) называют ограниченной инверсией приоритетов. В этом промежутке наблюдается логическое несоответствие с правилами планирования - задача с более высоким приоритетом находится в ожидании в то время как низкоприоритетная задача выполняется.

Но это еще не самое страшное. Допустим в системе работают три задачи: низкоприоритетная (А), со средними приоритетом (Б) и высокоприоритетная (В):

 Неограниченная инверсия приоритетов

Если ресурс заблокирован задачей (А), а он требуется задаче (В), то наблюдается та же ситуация - высокоприоритетная задача блокируется. Но допустим, что задача (Б) вытеснила (А), после того как (В) ушла в ожидание ресурса. Задача (Б) ничего не знает о конфликте, поэтому может выполняться сколь угодно долго на промежутке времени (T5-T4). Кроме того, кроме (Б) в системе могут быть и другие задачи, с приоритетами больше (А), но меньше (Б). Поэтому длительность периода (T6-T3) в общем случае неопределена. Такую ситуацию называют неограниченной инверсией приоритетов.

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

  • Протокол наследования приоритета (Priority inheritance protocol)
  • Протокол увеличения приоритета (Priority ceiling protocol)

Протокол наследования приоритета

Допустим в системе существуют две задачи с низким (А) и высоким (Б) приоритетом:

 Протокол наследования приоритета

В момент T2 задача (Б) вытесняет низкоприоритетную задачу (А) и затем в момент времени T3 пытается захватить заблокированный (А) ресурс.

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

После того как задача (А) разблокирует ресурс, ее приоритет понижается до исходного.

Протокол увеличения приоритета

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

Допустим в системе существуют три задачи с низким (А), средним (Б) и высоким (В) приоритетом, которые могут заблокировать один ресурс:

 Протокол увеличения приоритета

В момент времени T3, когда задача (Б) пытается захватить заблокированный (А) ресурс, приоритет (А) повышается до приоритета задачи (В), т.е. до максимального приоритета из всех задач, которые могут владеть ресурсом. Как только задача (А) освобождает ресурс в момент времени T4, ее приоритет понижается до исходного, а приоритет задачи (Б), ожидавшей ресурс повышается до (В).

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

Взаимная блокировка

Взаимная блокировка - это аварийное состояние системы, которое может возникать при вложенности блокировок ресурсов. Допустим в системе существуют две задачи с низким (А) и высоким (Б) приоритетом, которые используют два ресурса - X и Y:

 Взаимная блокировка

В момент времени T1 задача (А) блокирует ресурс X. Затем в момент времени T2 задачу (А) вытесняет более приоритетная задача (Б), которая в момент времени T3 блокирует ресурс Y. Если задача (Б) попытается заблокировать ресурс X (T4) не освободив ресурс Y, то она будет переведена в состояние ожидания, а выполнение задачи (А) будет продолжено. Если в момент времени T5 задача (А) попытается заблокировать ресурс Y, не освободив X, возникнет состояние взаимной блокировки - ни одна из задач (А) и (Б) не сможет получить управление.

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

Структура управления мютексом

В TNKernel реализованы мютексы как с протоколом наследования приоритета, так и с протоколом увеличения приоритета.

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

Каждый мютекс ассоциируется со структурой управления:

typedef struct _TN_MUTEX_S
{
    CDLL_QUEUE_S        wait_queue;
    CDLL_QUEUE_S        mutex_queue;
    CDLL_QUEUE_S        lock_mutex_queue;
    TN_UWORD            attr;
 
    TN_TCB_S          * holder;
    TN_UWORD            ceil_priority;
    TN_WORD             cnt;
    TN_OBJ_ID           id_mutex;
} TN_MUTEX_S;

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

wait_queue Очередь задач, ожидающих освобождение мютекса
mutex_queue Элемент списка заблокированных задачей мютексов
lock_mutex_queue Системная очередь заблокированных мютексов
attr Атрибут (тип обхода инверсии приоритетов) мютекса
holder Указатель на TCB задачи, блокирующей мютекс
ceil_priority Максимальный приоритет из задач, которые могут использовать ресурс (требуется для протокола увеличения приоритета)
cnt Зарезервировано
id_mutex Поле идентификации объекта как мютекса

Структура мютекса доступна только при определении TN_DEBUG. Тем не менее, прямой доступ к элементам структуры мютекса крайне не рекомендуется, так как это является вмешательством в работу планировщика и других сервисов RTOS.

Сервисы управления мютексами

TNKernel имеет следующий набор функций (сервисов) для управления мютексами:

Сервис Описание Свойства
Создание и удаление мютекса
  tn_mutex_create() Создание мютекса Разрешен вызов в контексте задачи и в прерывании
  tn_mutex_delete() Удаление мютекса Разрешен вызов только в контексте задачи Может привести к переключению контекста
Блокировка мютекса
  tn_mutex_lock() Блокировка мютекса Разрешен вызов только в контексте задачи Может привести к переключению контекста Сервис использует таймаут
  tn_mutex_lock_polling() Попытка блокировки мютекса без блокировки задачи Разрешен вызов только в контексте задачи Может привести к переключению контекста
Освобождение мютекса
  tn_mutex_unlock() Освобождение мютекса Разрешен вызов только в контексте задачи Может привести к переключению контекста
 
tnkernel/ref/mutex/intro.txt · Последние изменения: 21.07.2008 01:41 От admin
 
Creative Commons License Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki