Вход/Регистрация
Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
вернуться

Кёртен Роб

Шрифт:

Здесь мы можем столкнуться с новой проблемой. Как «потребителю» сбрасывать флаг data_ready согласованно с «производителем»? Очевидно, нам понадобится некоторая форма монопольного доступа к флагу, чтобы в любой момент времени только один из этих потоков мог модифицировать его. Метод, который применен в данном случае, заключается в применения мутекса, но это внутренний мутекс библиотеки ждущих блокировок, так что мы сможем обращаться к нему только с помощью двух функций: pthread_sleepon_lock и pthread_sleepon_unlock. Давайте модифицируем наш поток-«потребитель»:

consumer {

 while (1) {

pthread_sleepon_lock;

while (!data_ready) {

// WAIT

}

// Обработать данные

data_ready = 0;

pthread_sleepon_unlock;

 }

}

Здесь мы добавили «потребителю» установку и снятие блокировки. Это означает, что потребитель может теперь надежно проверять флаг data_ready, не опасаясь гонок, а также надежно его устанавливать.

Великолепно! А как насчет собственно процесса ожидания? Как мы и предполагали ранее, там действительно применяется вызов функции pthread_sleepon_wait. Вот второй while-цикл:

while (!data_ready) {

 pthread_sleepon_wait(&data_ready);

}

Функция pthread_sleepon_wait в действительности выполняет три действия:

1. Разблокирует мутекс библиотеки ждущих блокировок.

2. Выполняет собственно операцию ожидания.

3. Снова блокирует мутекс библиотеки ждущих блокировок.

Причина обязательной разблокировки/блокировки мутекса библиотеки проста: поскольку суть мутекса состоит в обеспечении взаимного исключения доступа к флагу data_ready, мы хотим запретить потоку-«производителю» изменять флаг data_ready, пока мы его проверяем. Но если мы не разблокируем флаг впоследствии, то поток-«производитель» не сможет его установить, чтобы сообщить нам о доступности данных! Операция повторной блокировки выполняется автоматически исключительно для удобства, чтобы вызвавший функцию pthread_sleepon_wait поток не беспокоился о состоянии блокировки после «пробуждения».

Давайте перейдем теперь к потоку-«производителю» и рассмотрим, как он использует библиотеку ждущих блокировок. Вот его полная реализация:

producer {

 while (1) {

// Ждать прерывания от оборудования...

pthread_sleepon_lock;

data_ready = 1;

pthread_sleepon_signal(&data_ready);

pthread_sleepon_unlock;

 }

}

Как вы видите, поток-«производитель» также блокирует мутекс, чтобы получить монопольный доступ к флагу data_ready перед его установкой.

Клиента «пробуждает» не установка флага data_ready в единицу (1), а вызов функции pthread_sleepon_signal!

Давайте рассмотрим происходящее в подробностях. Определим состояния «потребителя» и «производителя» следующим образом:

Состояние Означает
CONDVAR ожидание соответствующей ждущей блокировке условной переменной
MUTEX ожидание мутекса
READY состояние готовности, т.е., готов выполняться или уже выполняется
INTERRUPT ожидание прерывания от аппаратных средств
Действие Владелец мутекса Состояние «потребителя» Состояние «производителя»
«потребитель» блокирует мутекс «потребитель» READY INTERRUPT
«потребитель» проверяет флаг data_ready «потребитель» READY INTERRUPT
потребитель вызывает функцию pthread_sleepon_wait «потребитель» READY INTERRUPT
функция pthread_sleepon_wait разблокирует мутекс мутекс свободен READY INTERRUPT
функция pthread_sleepon_wait блокируется мутекс свободен CONDVAR INTERRUPT
пауза до прерывания мутекс свободен CONDVAR INTERRUPT
аппаратные средства генерируют данные мутекс свободен CONDVAR READY
«производитель» блокирует мутекс «производитель» CONDVAR READY
«производитель» устанавливает флаг data_ready «производитель» CONDVAR READY
«производитель» вызывает pthread_sleepon_signal «производитель» CONDVAR READY
«потребитель» «пробуждается», функция pthread_sleepon_wait пытается заблокировать мутекс «производитель» MUTEX READY
«производитель» разблокирует мутекс мутекс свободен MUTEX READY
«потребитель» получает мутекс «потребитель» READY READY
«потребитель» обрабатывает данные «потребитель» READY READY
«производитель» ждет новых данных от аппаратуры «потребитель» READY INTERRUPT
пауза («потребитель» обрабатывает полученные данные) «потребитель» READY INTERRUPT
«потребитель» завершает обработку и разблокирует мутекс мутекс свободен READY INTERRUPT
«потребитель» возвращается в начало цикла и блокирует мутекс «потребитель» READY INTERRUPT

Последняя строка в таблице повторяет первую — мы совершили один полный цикл.

Каково назначение флага data_ready? Он служит для двух целей:

• Он является флагом состояния — посредником между «потребителем» и «производителем», указывающим на состояние системы. Если флаг установлен в состояние 1, это означает, что данные доступны для обработки; если этот флаг установлено в состояние 0, это означает, что данных нет, и поток-потребитель должен быть заблокирован.

  • Читать дальше
  • 1
  • ...
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: