Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
IPC.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
536.06 Кб
Скачать

Флаги канала

_NTO_CHF_FIXED_PRIORITY

Принимающий поток не изменит приоритет в зависимости от приоритета отправителя. Если этот флаг не установлен, то приоритет принимающего сообщение потока изменяется на приоритет потока-отправителя.

_NTO_CHF_UNBLOCK

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

_NTO_CHF_THREAD_DEATH

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

_NTO_CHF_DISCONNECT

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

_NTO_CHF_SENDER_LEN

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

Флаг _NTO_CHF_UNBLOCK

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

Если сервер не устанавливает флаг _NTO_CHF_UNBLOCK, то клиент может разблокироваться от MsgSend() (или MsgSendv(), MsgSendvs() или другой функции этого семейства) когда захочет (например, по приему сигнала или по тайм-ауту ядра).

Если сервер устанавливает флаг _NTO_CHF_UNBLOCK, то клиент не может разблокироваться без посылки сервером сообщения по MsgReply() и, следовательно, может оказаться в состоянии dead line.

При однопоточном сервере происходит следующее:

Состояние клиента Состояние сервера

----------------------------------------------------------------------------------------------------

Клиент посылает запрос серверу Блокирован Обработка

Клиент получает сигнал Блокирован Обработка

Клиент передает импульс серверу Блокирован Обработка (первого сообщения)

Сервер завершает обработку Разблокирован, получены Обработка

первого запроса и отвечает клиенту корректные данные (импульса)

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

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

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

• Не выполнять задание клиента в потоке непосредственно, а поставить его в очередь заданий.

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

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

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

В обоих случаях сервер обязан ответить клиенту, иначе клиент останется заблокированным.

При многопоточном сервере происходит следующее:

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

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

Здесь мы имеем ситуацию с двумя параллельными потоками обработки (один вызван сообщением клиента и один — импульсом). Обычно в таких ситуациях применяются мутексы.

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

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

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]