Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
Шрифт:
Несколько
• Если сообщение с данными прибывает, когда либо никто не ждет, либо список ожидающих клиентов переполнен, в стандартный поток ошибок выводится сообщение, но клиенту при этом мы не отвечаем ничего. Это означает, что ряд клиентов может оказаться в REPLY-блокированном состоянии навсегда — идентификаторы отправителей мы потеряли, а значит, и ответ им дать не можем.
Это сделано намеренно. Вы можете изменить это, добавив соответственно сообщения MT_NO_WAITERS и MT_NO_SPACE, которыми можно было бы отвечать всякий раз при обнаружении ошибок данного типа.
• Когда клиент-обработчик ждет, а клиент-поставщик пересылает ему данные, мы отвечаем обоим клиентам. Это критично, поскольку мы должны разблокировать обоих клиентов.
• Мы повторно использовали буфер клиента-поставщика для обоих ответов. Этот прием программирования — опять же, вопрос стиля: в большом приложении у вас, вероятно, было бы много типов возвращаемых значений, и вы могли бы и не захотеть повторно использовать одни и те же буферы.
• В приведенном примере используется «щербатый» массив фиксированной длины с флагом «элемент задействован» (
• Когда функция MsgReceive получает импульс, наше решение относительно того, действительно ли это «наш» импульс, фактически является весьма слабо аргументированным — мы просто предполагаем (согласно комментариям), что все входящие импульсы имеют тип CODE_TIMER. Опять же, в конечном продукте следовало бы проверять значение кода импульса и сообщать о наличии каких-либо аномалий.
Отметим, что в приведенном примере демонстрируется только один способ реализации тайм-аутов клиентуры. Позже, в этой же главе (в разделе «Тайм-ауты ядра») мы поговорим о тайм-аутах ядра. Это еще один способ делать почти то же самое, только управление на этот раз осуществляется клиентом, а не таймером.
Здесь мы имеем несколько другое применение для периодических сообщений о тайм-аутах, когда эти сообщения предназначены сервером исключительно для внутреннего использования и не имеют никакого отношения к клиенту вообще.
Например, некоторые аппаратные средства могут требовать, чтобы сервер опрашивал их периодически — например, такое может быть в случае сетевого соединения: сервер должен периодически проверять, является ли данное подключение доступным, и это не зависит от команд клиентуры.
Другой вариант — если, например, в аппаратных средствах предусмотрен таймер «выключения по неактивности». Например, если длительное пребывание какого-то аппаратного модуля во включенном состоянии может приводить к неоправданным затратам электроэнергии, то если его никто не использует в течение,
Код в этом случае сильно бы напоминал приведенный выше пример, за исключением того, что вместо списка ожидающих клиентов у вас была бы только одна переменная тайм-аута. С каждым событием от таймера ее значение уменьшалось бы, но пока оно больше нуля, ничего бы не происходило. Когда оно стало бы равным нулю, это вызывало бы отключение аппаратных средств (или какое-либо другое соответствующее действие).
Единственный трюк здесь заключается в том, что всякий раз, когда поступает сообщение от клиента, использующего данные аппаратные средства, вы должны восстановить первоначальное значение этой переменной, поскольку обращение к ресурсу должно сбрасывать «обратный отсчет». И наоборот, аппаратным средствам может потребоваться определенный промежуток времени «на разогрев» после включения. В этом случае после выключения аппаратных средств вам придется при поступлении запроса от клиента организовать еще один таймер, чтобы «придержать» запрос до того момента, пока аппаратные средства не станут готовы.
Таймеры, посылающие сигналы
На настоящий момент мы уже рассмотрели практически все, что относится к таймерам, за исключением одного небольшого момента. Мы обеспечивали отправку импульса, но у нас также есть возможность посылать POSIX-сигналы. Давайте посмотрим, как это делается:
Это простейший способ создать таймер, который будет посылать вам сигнал. Он обеспечивает выдачу сигнала SIGALRM при срабатывании таймера. Если бы мы предоставили
Это обеспечит нам выдачу сигнала SIGUSR1 вместо SIGALRM.
Сигналы таймера перехватываются обычными обработчиками сигналов, здесь нет ничего необычного.
Таймеры, создающие потоки
Если вы хотите по каждому срабатыванию таймера создавать новый поток, то вы можете это сделать с помощью
Однако, пользоваться этим надо очень осторожно, потому что если вы определите слишком короткий интервал, вы можете просто утонуть в создаваемых потоках. Они просто поглотят все ресурсы вашего процессора и оперативной памяти.
Опрос и установка часов реального времени, и кое-что еще
Независимо от применения таймеров, вы можете также опрашивать и устанавливать часы реального времени, а также и плавно подстраивать их. Для этих целей можно использовать следующие функции: