Поведение именованного канала Win32 в дуплексном режиме - PullRequest
0 голосов
/ 21 октября 2019

Попытка чтения и записи через именованный канал между одним сервером и одним клиентом без перекрывающегося режима. Две темы запускаются для чтения и записи отдельно. Насколько я понимаю в документации, одно соединение будет иметь как входной, так и выходной буфер. Так что я должен уметь читать и писать параллельно с одним экземпляром канала. Написали простой тестовый код для записи от сервера к клиенту в цикле. В тот момент, когда поток чтения на сервере вызывает ReadFile, поток записи застревает в WriteFile. Может ли кто-нибудь объяснить, каково поведение в этом случае?

Документация говорит " Сервер канала не должен выполнять операцию блокирующего чтения, пока клиент канала не запустил ". Но блокировка ReadFile выполняется после того, как клиент начинает получать данные из потока записи.

Обновление 1: я понимаю, что ReadFile блокирует здесь WriteFile. Но я ищу документацию Microsoft, в которой есть объяснение такого поведения. Любые ссылки на это будут высоко оценены.

1 Ответ

2 голосов
/ 21 октября 2019

В тот момент, когда поток чтения на сервере вызывает ReadFile, поток записи застревает в WriteFile.

На канал ссылаются два объекта файла ядра (см. FILE_OBJECT), по одному на каждом конце трубы. На стороне сервера CreateNamedPipe внутренне вызывает собственную системную функцию NtCreateNamedPipeFile, которая в ядре вызывает IoCreateFile, при этом CreateFileType передается какCreateFileTypeNamedPipe.

Каждый файловый объект может быть открыт для синхронного или асинхронного ввода-вывода . (Асинхронный ввод / вывод также называется перекрывающимся вводом / выводом.) Режим ввода / вывода определяется наличием флага FO_SYNCHRONOUS_IO в объекте файла. Если флаг установлен, режим ввода / вывода является синхронным. В противном случае режим ввода-вывода является асинхронным.

В синхронном режиме менеджер ввода-вывода сериализует все операции ввода-вывода с файловым объектом. Параллельные операции ввода-вывода над файлом в других потоках будут блокироваться (т. Е. Ждать начала) до завершения текущей операции. Даже запрос имени файла (также операция ввода / вывода) заблокирует. (Это известная проблема для инструментов системного уровня, таких как Sysinternals handle.exe. Она может блокироваться, если мы попытаемся запросить имя канала, пока система ожидает завершения синхронного чтения.)

Использование несколькихтемы (например, чтение в одной теме, запись в другой) здесь не помогает вообще. Асинхронный ввод / вывод здесь идеален. Он более эффективен (меньше потоков) и никогда не блокируется.


Собственный NT API и Windows API используют различные параметры для задания режима ввода / вывода.

NT API (например, NtCreateFile, NtCreateNamedPipeFile) по умолчанию предполагает асинхронный режим. Использование синхронного режима требует определенной опции создания, как описано в документации:

Флаги FILE_SYNCHRONOUS_IO_ALERT и FILE_SYNCHRONOUS_IO_NONALERT CreateOptions , которые являются взаимоисключающими, как следует из их имен,укажите, что все операции ввода-вывода в файле будут синхронными, если они выполняются через объект файла, на который ссылается возвращенный FileHandle. Все операции ввода-вывода в таком файле сериализуются во всех потоках с использованием возвращенного дескриптора.

При любом из параметров создания в объекте файла устанавливается флаг FO_SYNCHRONOUS_IO. FILE_SYNCHRONOUS_IO_ALERT дополнительно устанавливает флаг FO_ALERTABLE_IO.

API Windows (например, CreateFileW, CreateNamedPipeW, CreatePipe) по умолчанию предполагает режим синхронного ввода-вывода. Для этого он передает опцию создания NT FILE_SYNCHRONOUS_IO_NONALERT при вызове базовых функций NT API. Флаг Windows API FILE_FLAG_OVERLAPPED переопределяет значение по умолчанию для запроса режима асинхронного ввода-вывода.

...