Блокирование в пределах администратора ресурсов
Блокирование в пределах администратора ресурсов
До настоящего момента мы избегали разговоров о возможности блокирования в пределах администратора ресурсов. Мы предполагали, что у нас есть функция-обработчик (например, io_read()), и что данные будут доступны немедленно. А что если нам придется блокироваться в ожидании данных? Например, выполнение read() применительно к последовательному порту может потребовать блокирования до приема символа. Очевидно, что мы не можем предсказать, сколько может продолжаться такое ожидание.
Блокирование в пределах администратора ресурсов базируется на тех же самых принципах, которые мы обсуждали в главе «Обмен сообщениями» — в конце концов, администратор ресурса фактически является сервером, который обрабатывает рад четко определенных сообщений. Когда прибывает сообщение, соответствующее клиентскому запросу read(), оно прибывает вместе с идентификатором отправителя (receive ID), и клиент блокируется. Если у администратора ресурсов есть данные, он просто возвращает их клиенту, как мы уже видели в различных приведенных ранее примерах. Однако, если данные недоступны, администратор ресурсов должен будет удерживать этого клиента в заблокированном состоянии (конечно, если клиент для этой операции определил блокирующий режим), чтобы иметь возможность продолжить обработку других сообщений. Реально это означает, что поток администратора ресурсов, который принял сообщение от клиента, не должен блокироваться в ожидании данных — в противном случае это может закончиться для администратора ресурсов огромным числом заблокированных потоков, каждый из которых ожидал бы данные от некоего устройства.
Правильным решением для этой проблемы является сохранение идентификатора отправителя полученного сообщения в какой-нибудь очереди и возврат из вашего обработчика константы _RESMGR._NOREPLY. Это укажет библиотеке администратора ресурсов, что обработка сообщения закончена, но клиента пока разблокировать не надо.
Несколько позже, по готовности данных, вы сможете выбрать идентификатор отправителя нужного клиента и сконструировать ответное сообщение с данными. После этого можно отвечать клиенту.
Вы могли бы также расширить эту концепцию добавлением тайм-аутов, как мы это делали в главе «Часы, таймеры и периодические уведомления» (параграф «Поддерживаемые сервером тайм-ауты»). Если говорить вкратце, там по истечении некоторого интервала времени клиентский запрос считался «просроченным», и сервер отвечал по сохраненному по идентификатору отправителя неким сообщением об ошибке.