Блокировка блокировки ReadFile() - именованная труба (Windows API)
Чтобы упростить, это ситуация, когда NamedPipe SERVER ожидает, что КЛИЕНТ NamedPipe будет писать в трубу (используя WriteFile())
В Windows API, который блокируется, является ReadFile()
Сервер создал синхронный канал (без перекрытия ввода-вывода) с включенной блокировкой
Клиент подключился, и теперь сервер ждет некоторых данных.
В обычном потоке вещей клиент отправляет некоторые данные, а сервер обрабатывает их, а затем возвращается в ReadFile(), чтобы дождаться следующего фрагмента данных.
Между тем происходит событие (например, пользовательский ввод), и NamedPipe SERVER должен выполнить другой код, который он не может сделать, пока блокирует ReadFile().
В этот момент я должен упомянуть, что клиент NamedPipe не является моим приложением, поэтому я не контролирую его. Я не могу заставить его отправить несколько байтов, чтобы разблокировать сервер. Он просто сидит и не посылает никаких данных. Поскольку я не контролирую реализацию Клиента, я ничего не могу изменить с этой целью.
Одним из решений было бы создать отдельный поток, в котором выполняются все операции ReadFile(). Таким образом, когда событие происходит, я могу просто обработать код. Проблема в том, что для события также требуется отдельный поток, поэтому теперь у меня есть два дополнительных потока для каждого экземпляра этого сервера. Поскольку это должно быть масштабируемым, это нежелательно.
Из другого потока, который я пробовал, звонил
DisconnectNamedPipe()
и
CloseHandle()
оба они не вернутся (пока клиент не напишет в трубку.)
Я не могу подключиться к одному и тому же каналу и написать несколько байтов, потому что:
"Все экземпляры именованного канала имеют одинаковое имя канала, но каждый экземпляр имеет
его собственные буферы и дескрипторы и предоставляет отдельный канал для клиента/сервера
связь ".
http://msdn.microsoft.com/en-us/library/aa365590.aspx
Мне нужен способ подделать его, поэтому вопрос стоимостью $64 000 долларов:
Как я могу разбить блокировку ReadFile()?
Ответы
Ответ 1
Попробуйте это перед 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--
Ответ 2
Взгляните на CancelSynchronousIo
Отмечает ожидающий синхронный ввод-вывод операции, выпущенные указанный поток отменен.
И CancelIo/CancelIoEx:
Отменить все ожидающие асинхронные операции ввода-вывода выполните следующие действия:
CancelIo - эта функция отменяется только операции, выданные вызывающим thread для указанного дескриптора файла.
CancelIoEx - эта функция отменяет все операции, выпущенные потоками для указанный дескриптор файла.
Ответ 3
Майк,
Вы не можете отменить синхронный ReadFile. Но вы можете переключиться на асинхронные (перекрывающиеся) операции. Делая это, вы можете реализовать довольно масштабируемую архитектуру.
Возможный алгоритм (просто идея):
- Для каждого нового клиентского вызова ReadFile
- WaitForMultipleObjects, где ручки перекрываются. hEvent + your
пользовательские события
- Итерация по сигнальным событиям и планирование их выполнения потоками из пула потоков.
Таким образом, вы можете иметь только несколько потоков для получения соединений и чтения данных, тогда как фактическая обработка данных может выполняться пулом потоков.
Ответ 4
Проблема с этим заключается в том, что событие также требует отдельного потока, поэтому теперь у меня есть два дополнительных потока для каждого экземпляра этого сервера. Поскольку это должно быть масштабируемым, это нежелательно.
Никогда в моей карьере я не обнаружил, что "больше потоков" == "менее масштабируемо". Сколько из этих "серверных" экземпляров у вас есть?
Обычно операция должна выполняться в отдельном потоке, если эта операция будет блокироваться, и система должна реагировать, когда операция заблокирована.
Ответ 5
Асинхронные операции ввода-вывода не должны блокировать нить, если они используют порты завершения ввода-вывода. См.: http://msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx
Ответ 6
Что происходит, так это исходящий канал сервера остается открытым, ожидая соединения, пока ваш клиент пытается подключиться к входящему каналу сервера (который больше не существует). Что вам нужно сделать, это вымыть ваш исходящий канал в чтобы вернуться к вашему входящему. Вы можете выполнить очистку на стороне клиента, прочитав файл (не забудьте установить соединение для подключения, потому что там есть "рукопожатие", и оно никогда не будет работать в первый раз)