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

Кёртен Роб

Шрифт:

В действительности это составная операция. Вот как это работает:

1. Клиент создает структуру типа

struct sigevent
и заполняет ее.

2. Клиент посылает сообщение серверу, в котором запрашивает: «Сделай для меня то-то, ответ дай сразу же, а по окончании работы уведоми меня об этом при помощи структуры

struct sigevent
— структуру прилагаю».

3. Сервер принимает сообщение (которое включает в себя структуру

struct sigevent
), сохраняет структуру
struct sigevent
и идентификатор отправителя и немедленно отвечает клиенту.

4. Теперь клиент выполняется — как и сервер.

5. Когда сервер завершает работу, он использует функцию MsgDeliverEvent, чтобы сообщить об этом клиенту.

Мы рассмотрим более подробно структуру

struct sigevent
в главе «Часы, таймеры и периодические уведомления», в параграфе «Как заполнить структуру
struct sigevent
», а здесь мы только предположим, что структура
struct sigevent
— это «черный ящик», который содержит некоторое событие, используемое сервером для уведомления клиента.

Поскольку сервер хранит клиентские

struct sigevent
и идентификатор отправителя, он теперь сервер может вызвать функцию MsgDeliverEvent, чтобы доставить событие клиенту, как клиент того и желал:

int MsgDeliverEvent(int rcvid, const struct sigevent *event);

Обратите внимание, что функция MsgDeliverEvent принимает два параметра — идентификатор отправителя (rcvid) и доставляемое событие (event). Сервер никогда не изменяет и даже не читает событие! Этот момент важен, потому что это позволяет серверу доставлять события вне зависимости от их выбранного клиентом типа, без какой бы то ни было специальной обработки на стороне сервера.

Идентификатор rcvid — это идентификатор отправителя, который сервер получил от клиента. Заметьте, что это определенно особый случай. Обычно, после того как сервер ответил клиенту, идентификатор отправителя прекращает иметь значение (потому что клиент уже разблокирован, и сервер не может разблокировать его заново или считать/записать данные, и т.п.). Но в нашем случае, идентификатор отправителя содержит только информацию для ядра, какому клиенту должно быть доставлено событие. Вызывая MsgDeliverEvent, сервер не блокируется — для сервера это неблокирующий вызов. Ядро доставляет событие клиенту, после чего тот выполняет какие бы то ни было соответствующие действия.

Флаги канала

Когда мы вначале книги изучали сервер (в параграфе «Сервер»), мы упомянули, что функция ChannelCreate принимает параметр flags (флаги); правда, тогда мы вместо этого параметра передавали нуль.

Теперь пришло время более подробно изучить назначение параметра flags. Рассмотрим только некоторые из возможных его значений:

_NTO_CHF_FIXED_PRIORITY

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

_NTO_CHF_UNBLOCK

Ядро посылает импульс всякий раз, когда поток клиента пытается разблокироваться. Чтобы клиент мог разблокироваться, сервер должен ему ответить. Мы обсудим это ниже, потому что это имеет некоторые интересные последствия — как для клиента, так и для сервера.

_NTO_CHF_THREAD_DEATH

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

_NTO_CHF_DISCONNECT

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

_NTO_CHF_SENDER_LEN

Ядро доставляет серверу, наряду с остальной информацией, размер клиентского сообщения.

Флаг _NTO_CHF_UNBLOCK

Присмотримся к флагу _NTO_CHF_UNBLOCK. Этот флаг имеет несколько особенностей при его применении, интересных и для клиента, и для сервера.

Обычно (то есть когда сервер не устанавливает флаг _NTO_CHF_UNBLOCK), когда клиент хочет разблокироваться от MsgSend (или MsgSendv, MsgSendvs или другой функции этого семейства), клиент просто берет и разблокируется. Клиент может пожелать разблокироваться по приему сигнала или по тайм-ауту ядра (см. функцию TimerTimeout в Справочном руководстве по Си-библиотеке, а также главу «Часы, таймеры и периодические уведомления»). Неприятный аспект этого заключается в том, что сервер понятия не имеет, что клиент уже разблокирован и больше не ожидает ответа.

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

Не забывайте: поток сервера по-прежнему обрабатывает поступивший от клиента запрос. Но так как клиент теперь разблокирован (например, его вызов MsgSend возвратил EINTR), он теперь может послать серверу другой запрос. Вследствие особенности архитектуры серверов в QNX/Neutrino, очередное сообщение от этого клиента принял бы другой поток сервера, но идентификатор отправителя-то остается тем же самым! Сервер не сумеет различить эти два запроса, и когда первый поток сервера завершает обработку первого запроса и отвечает клиенту, фактически он отвечает на второе сообщение, а не на первое. Итак, первый поток сервера отвечает на второе сообщение клиента.

  • Читать дальше
  • 1
  • ...
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • ...

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

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

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

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