Снятие блокировки ReadFile () - именованный канал (Windows API) - PullRequest
22 голосов
/ 27 февраля 2009

Для простоты, это ситуация, когда NamedPipe SERVER ожидает, когда клиент NamedPipe выполнит запись в канал (используя WriteFile ())

Windows API, который блокирует, является ReadFile ()

Сервер создал синхронный канал (без перекрывающихся операций ввода-вывода) с включенной блокировкой

Клиент подключился, и теперь сервер ожидает некоторые данные.

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

Между тем происходит событие (например, пользовательский ввод), и СЕРВЕР NamedPipe должен теперь выполнить какой-то другой код, который он не может сделать, пока ReadFile () блокирует.

На данный момент я должен отметить, что Клиент NamedPipe не является моим приложением, поэтому я не могу его контролировать. Я не могу заставить его отправить несколько байтов, чтобы разблокировать сервер. Он просто собирается сидеть и не отправлять данные. Поскольку у меня нет контроля над реализацией клиента, я ничего не могу изменить в этом отношении.

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

Из другого потока я пытался позвонить

 DisconnectNamedPipe()

и

 CloseHandle()

они оба не вернутся (пока клиент не запишет в канал.)

Я не могу подключиться к одному каналу и записать несколько байтов, потому что:

"Все экземпляры именованного канала совместно используют одно и то же имя канала, но каждый экземпляр имеет свои собственные буферы и дескрипторы, и обеспечивает отдельный канал для клиента / сервера связь. "

http://msdn.microsoft.com/en-us/library/aa365590.aspx

Мне нужен способ подделать его, так что вопрос в $ 64 тыс.:

Как я могу снять блокировку ReadFile ()?

Ответы [ 6 ]

14 голосов
/ 04 августа 2009

Попробуйте это перед ReadFile:

BOOL WINAPI PeekNamedPipe(
  __in       HANDLE hNamedPipe,
  __out_opt  LPVOID lpBuffer,
  __in       DWORD nBufferSize,
  __out_opt  LPDWORD lpBytesRead,
  __out_opt  LPDWORD lpTotalBytesAvail,
  __out_opt  LPDWORD lpBytesLeftThisMessage
);

if(TotalBytesAvail > 0)
  ReadFile(....);

-AV-

6 голосов
/ 27 февраля 2009

Посмотрите на CancelSynchronousIo

Помечает в ожидании синхронного ввода-вывода операции, которые выдаются указанный поток отменен.

И CancelIo / CancelIoEx:

Для отмены всех ожидающих асинхронного ввода-вывода операции, используйте либо:

CancelIo - эта функция отменяет только операции, выданные вызывающим поток для указанного дескриптора файла.

CancelIoEx - эта функция отменяет все операции, выданные потоками для указанный дескриптор файла.

3 голосов
/ 27 февраля 2009

Mike

Вы не можете отменить синхронный ReadFile. Но вы можете переключиться на асинхронные (перекрытые) операции. Делая это, вы можете реализовать довольно масштабируемую архитектуру.

Возможный алгоритм (просто идея):

  • Для каждого нового клиента вызывайте ReadFile
  • WaitForMultipleObjects, где маркеры перекрываются. HEvent + your пользовательские события
  • Перебирать сигнальные события и планировать их выполнение потоками из пула потоков.

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

2 голосов
/ 27 февраля 2009

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

Никогда в своей карьере я не обнаружил, что "больше потоков" == "менее масштабируемо". Сколько у вас таких «серверных» экземпляров?

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

1 голос
/ 23 марта 2017

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

1 голос
/ 04 июня 2009

Операции асинхронного ввода-вывода не должны блокировать какой-либо поток, если они используют порты завершения ввода-вывода. Смотри: http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx

...