Многопоточный ввод/вывод с использованием именованных каналов применен в сервере с многопоточной поддержкой, который рассматривался в главе 11. Программа grepMT (программа 7.1) управляет параллельным выполнением операций ввода/вывода с участием нескольких файлов. Таким образом, мы уже располагаем рядом программ, которые выполняют многопоточный ввод/вывод и тем самым обеспечивают одну из форм асинхронного ввода/вывода.
Перекрывающийся ввод/вывод является предметом рассмотрения следующего раздела, а в приведенных в нем примерах, реализующих преобразование файлов (из ASCII в UNICODE), эта методика применена для иллюстрации возможностей последовательной обработки файлов. С этой целью используется видоизмененный вариант программы 2.4. Вслед за перекрывающимся вводом/выводом рассматривается расширенный ввод/вывод, использующий процедуры завершения.
Примечание
Методы перекрывающегося и расширенного ввода/вывода часто оказываются сложными в реализации, редко обеспечивают какие-либо преимущества в отношении производительности, иногда даже становясь причиной ее ухудшения, а в случае файлового ввода/вывода способны работать лишь под управлением Windows NT. Эти проблемы преодолеваются с помощью потоков, поэтому, вероятно, многие читатели захотят сразу же перейти к разделам, посвященным таймерам ожидания и портам завершения ввода/вывода, возвращаясь к этому разделу по мере необходимости. С другой стороны, элементы асинхронного ввода/вывода присутствуют как в устаревших, так и в новых технологиях, в связи с чем эти методы все-таки стоит изучить.
Так, технология СОМ на платформе NT5 поддерживает асинхронный вызов методов, поэтому указанная методика может пригодиться многим читателям, которые используют или собираются использовать технологию СОМ. Кроме того, много общего с расширенным вводом/выводом имеют операции асинхронного вызова процедур (глава 10), и хотя лично я предпочитаю использовать потоки, другие могут отдать предпочтение именно этому механизму.
Перекрывающийся ввод/вывод
Первое, что необходимо сделать для организации асинхронного ввода/вывода, будь то перекрывающегося или расширенного, — это установить атрибут перекрывания (overlapped attribute) для файлового или иного дескриптора. Для этого при вызове CreateFile или иной функции, в результате которого создается файл, именованный канал или иной дескриптор, следует указать флаг FILE_FLAG_OVERLAPPED.
В случае сокетов (глава 12), независимо от того, были они созданы с использованием функции socket или accept, атрибут перекрывания устанавливается по умолчанию в Winsock 1.1, но должен устанавливаться явным образом в Winsock 2.0. Перекрывающиеся сокеты могут использоваться в асинхронном режиме во всех версиях Windows.
До этого момента структуры OVERLAPPED использовались нами совместно с функцией LockFileEx, а также в качестве альтернативы использованию функции SetFilePointer (глава 3), но они также являются существенным элементом перекрывающегося ввода/вывода. Эти структуры выступают в качестве необязательных параметров при вызове четырех приведенных ниже функций, которые могут блокироваться при завершении операций.
ReadFile
WriteFile
TransасtNamedPipe
ConnectNamedPipe
Вспомните, что при указании флага FILE_FLAG_OVERLAPPED в составе параметра dwAttrsAndFlags (в случае функции CreateFile) или параметра dwOpen-Mode (в случае функции CreateNamedPipe) соответствующие файл или канал могут использоваться только в режиме перекрывания. С анонимными каналами перекрывающийся ввод/вывод не работает.
Примечание
В документации по функции CreateFile есть упоминание о том, что использование флага FILE_FLAG_NO_BUFFERING улучшает характеристики быстродействия перекрывающегося ввода/вывода. Эксперименты показывают лишь незначительное повышение производительности (примерно на 15%, что может быть проверено путем экспериментирования с программой 14.1), но вы должны убедиться в том, что суммарный размер считываемых данных при выполнении операций ReadFile или WriteFile, кратен размеру сектора диска.
Перекрывающиеся сокеты
Одним из наиболее важных нововведений в Windows Sockets 2.0 (глава 12) является стандартизация перекрывающегося ввода/вывода. В частности, сокеты уже не создаются автоматически как дескрипторы файлов с перекрытием. Функция socket создает неперекрывающийся дескриптор. Чтобы создать перекрывающийся сокет, следует вызвать функцию WSASocket, явно запросив создание перекрывающегося совета путем указания значения WSA_FLAG_OVERLAPPED для параметра dwFlags функции WSASocket.