KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программное обеспечение » Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform

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

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Роб Кёртен, "Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform" бесплатно, без регистрации.
Перейти на страницу:

Оба параметра it_value и it_interval фактически являются структурами типа struct timespec — еще одного POSIX-объекта. Эта структура позволяет вам обеспечить разрешающую способность на уровне долей секунд. Первый ее элемент, tv_sec, — это число секунд, второй элемент, tv_nsec, — число наносекунд в текущей секунде. (Это означает, что никогда не следует устанавливать параметр tv_nsec в значение, превышающее 1 миллиард — это будет подразумевать смещение на более чем 1 секунду).

Несколько примеров:

it_value.tv_sec = 5;

it_value.tv_nsec = 500000000;

it_interval.tv_sec = 0;

it_interval.tv_nsec = 0;

Это сформирует однократный таймер, который сработает через 5,5 секунды. (5,5 секунд складывается из 5 секунд и 500,000,000 наносекунд.)

Мы предполагаем здесь, что этот таймер используется как относительный, потому что если бы это было не так, то его время срабатывания уже давно бы его истекло (5.5 секунд с момента 00:00 по Гринвичу, 1 января 1970).

Другой пример:

it_value.tv_sec = 987654321;

it_value.tv_nsec = 0;

it_interval.tv_sec = 0;

it_interval.tv_nsec = 0;

Данная комбинация параметров сформирует однократный таймер, который сработает в четверг, 19 апреля 2001 года в 00:25:21 по EDT. (Существует множество функций, которые помогут вам преобразовать воспринимаемый человеком интервал времени в «число секунд, истекшее с 00:00:00 по Гринвичу, 1 января 1970 года». См. функции time(), asctime(), ctime(), mktime(), strftime(), и т.д.).

В данном примере мы предполагаем, что это абсолютный таймер, поскольку в противном случае ждать пришлось бы достаточно долго (987654321 секунд — приблизительно 31.3 года).

Отметьте, что в двух приведенных выше примерах я говорил: «мы предполагаем». В коде функции timer_settime() нет никаких проверок на правильность аргументов! Вы должны самостоятельно доопределить, является таймер абсолютным или относительным. Что до ядра, то оно будет просто счастливо запланировать какое-нибудь событие на 31.3 года вперед.

И еще один пример:

it_value.tv_sec = 1;

it_value.tv_nsec = 0;

it_interval.tv_sec = 0;

it_interval.tv_nsec = 500000000;

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

Сервер с периодическими импульсами

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

• поддерживаемые сервером тайм-ауты клиентских запросов;

• внутренние периодические события серверов.

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

Поддерживаемые сервером тайм-ауты

В таком сценарии сервер предоставляет клиенту некоторую услугу, и клиент способен задать тайм-аут. Это может использоваться в самых разнообразных приложениях. Например, вы можете сказать серверу «выдай мне данные за 15 секунд» или «дай мне знать, когда истекут 10 секунд», или «жди прихода данных, но в течение не более чем 2 секунд».

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

Ниже приведен полный пример сервера, который принимает одно из двух сообщений от клиентуры и сообщения о тайм-ауте в виде импульса. Первое клиентское сообщение говорит серверу: «Дай мне знать, есть ли для меня данные, но не блокируй меня более чем на 5 секунд». Второе клиентское сообщение говорит: «Вот, возьми данные». Сервер должен позволить нескольким клиентам блокироваться на себе в ожидании данных, и поэтому обязан сопоставить клиентам тайм-ауты. Тут-то и нужен импульс; он информирует сервер: «Истекла одна секунда».

Чтобы программа не выглядела излишне громоздкой, перед каждым из основных разделов я прерываю исходный текст небольшими пояснениями. Скачать эту программу вы можете на FTP-сайте компании PARSE (ftp://ftp.parseftp.parse.com/pub/book_v3.tar.gz), файл называется time1.с.

Декларации

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

/*

 * time1.c

 *

 * Пример сервера, получающего периодические сообщения

 * от таймера

 * и обычные сообщения от клиента.

 *

 * Иллюстрирует использование функций таймера с импульсами.

*/

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

#include <signal.h>

#include <errno.h>

#include <unistd.h>

#include <sys/siginfo.h>

#include <sys/neutrino.h>


// Получаемые сообщения


// Сообщения

#define MT_WAIT_DATA 2 // Сообщение от клиента

#define MT_SEND_DATA 3 // Сообщение от клиента


// Импульсы

#define CODE_TIMER 1 // Импульс от таймера


// Отправляемые сообщения

#define MT_OK       0 // Сообщение клиенту

#define MT_TIMEDOUT 1 // Сообщение клиенту


// Структура сообщения

typedef struct {

 int messageType; // Содержит сообщение от клиента и

                  // клиенту

 int messageData; // Опциональные данные, зависят от

                  // сообщения

} ClientMessageT;


typedef union {

 ClientMessageT msg;  // Сообщение может быть

                      // либо обычным,

 struct _pulse pulse; // либо импульсом

} MessageT;


// Таблица клиентов

#define MAX_CLIENT 16 // Максимум клиентов

                      // одновременно


struct {

 int in_use;  // Элемент используется?

 int rcvid;   // Идентификатор

              // отправителя клиента

 int timeout; // Оставшийся клиенту

              //тайм-аут

} clients[MAX_CLIENT]; // Таблица клиентов


int chid; // Идентификатор канала

          // (глобальный)


int debug = 1; // Режим отладки, 1 ==

               // вкл, 0 == выкл


char *progname = "time1.c";


// Предопределенные прототипы

static void setupPulseAndTimer(void);

static void gotAPulse(void);

static void gotAMessage(int rcvid, ClientMessageT *msg);

main()

Следующий раздел кода является основным и отвечает за следующее:

• создание канала с помощью функции ChannelCreate();

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

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

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

Обработка импульсов и сообщений выполняется функциями gotAPulse() и gotAMessage().

int main void) // Игнорировать аргументы

               // командной строки

{

 int rcvid; // PID отправителя

 MessageT msg; // Само сообщение

 if ((chid = ChannelCreate(0)) == -1) {

  fprintf(stderr, "%s: не удалось создать канал!n",

   progname);

  perror(NULL);

  exit(EXIT_FAILURE);

 }

 // Настроить импульс и таймер

 setupPulseAndTimer();

 // Прием сообщений

 for(;;) {

  rcvid = MsgReceive(chid, &msg, sizeof(msg), NULL));

  // Определить, от кого сообщение

  if (rcvid == 0) {

   // Здесь неплохо бы еще проверить поле «code»...

   gotAPulse();

  } else {

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*