Common Intermediate Language и системное программирование в Microsoft.Net. Макаров А.В - 109 стр.

UptoLike

отреагировать на завершение операции (особенно на многопро-
цессорных машинах), однако ценой увеличения загрузки процес-
сора, что может снизить общую производительность системы.
Функция WriteFile возвращает значение TRUE, если операция за-
писи завершена синхронно, а в случае ошибки или начатой
асинхронной операции она возвращает FALSE, поэтому требует-
ся анализ кода возникшей «ошибки», которая может и не яв-
ляться ошибкой.
2. Выполнение асинхронных операций с ожиданием на объектах
ядра:
ov.Offset = 12345;
ov.hEvent = CreateEvent((LPSECURITY_ATTRIBUTES)NULL, TRUE, FALSE, 0);
if (
WriteFile( fh, buffer, sizeof(buffer), &dwWritten, &ov ) ||
GetLastError() == ERROR_IO_PENDING
) {
/* пока операция ввода-вывода выполняется, выполняем некоторые
операции...
дожидаемся завершения операции ввода-вывода */
GetOverlappedResult( fh, &ov, &dwWritten, TRUE );
} else {
/* возникла ошибка */
}
Функция GetOverlappedResult в данном случае проверяет состо-
яние операции и, если она еще не завершена, вызывает функ-
цию WaitForSingleObject для ожидания завершения операции
ввода-вывода. Объект «событие» можно не создавать – в этом
случае функция будет ожидать освобождения объекта «файл»;
однако в случае нескольких, накладывающихся друг на друга,
асинхронных операций будет непонятно, какая именно опера-
ция завершилась, и использование специфичных для каждой
операции событий снимает эту проблему.
Ожидание на объектах ядра является наиболее экономным, но
реакция приложения на завершение ввода-вывода связана с ра-
ботой планировщика, поэтому для достижения малых задержек
иногда надо дополнительно повышать приоритеты потоков, пе-
реходящих в режим ожидания завершения ввода-вывода.
3. Выполнение асинхронных операций с использованием функ-
ций завершения операций ввода-вывода. Эта функция будет ав-
томатически вызвана после завершения ввода-вывода и может
Основы многозадачности
205
HasOverlappedIoCompleted и некоторые другие. Существует несколько вари-
антов использования асинхронного ввода-вывода; рассмотрим их на
небольшом примере.
Для начала надо описать необходимые переменные и открыть файл с
разрешением асинхронных операций (FILE_FLAG_OVERLAPPED):
OVERLAPPED ov;
DWORD dwWritten;
BYTE buffer[ 5000000 ];
HANDLE fh = CreateFile(
“file.dat”, FILE_READ_DATA|FILE_WRITE_DATA,
FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL
);
if ( fh == INVALID_HANDLE_VALUE ) {
/* возникла ошибка */
}
ZeroMemory( &ov, sizeof(OVERLAPPED) );
FillMemory( buffer, sizeof(buffer), 123 );
1. Выполнение асинхронных операций с опросом состояния; этот
способ может обеспечить самую быструю реакцию на заверше-
ние операции ввода-вывода, но ценой более высокой загрузки
процессора:
ov.Offset = 12345;
if (
WriteFile( fh, buffer, sizeof(buffer), &dwWritten, &ov ) ||
GetLastError() == ERROR_IO_PENDING
) {
/* пока операция ввода-вывода выполняется,
выполняем некоторые операции.
дожидаемся завершения операции ввода-вывода */
while (!GetOverlappedResult(fh, &ov, &dwWritten, FALSE)){}
} else {
/* возникла ошибка */
}
Функция GetOverlappedResult в данном случае проверяет состоя-
ние операции ввода-вывода и возвращает признак ее завершения.
Опрос состояния операции в цикле позволяет наиболее быстро
204
CIL и системное программирование в Microsoft .NET
204                          CIL и системное программирование в Microsoft .NET   Основы многозадачности                                                 205


HasOverlappedIoCompleted и некоторые другие. Существует несколько вари-                    отреагировать на завершение операции (особенно на многопро-
антов использования асинхронного ввода-вывода; рассмотрим их на                            цессорных машинах), однако ценой увеличения загрузки процес-
небольшом примере.                                                                         сора, что может снизить общую производительность системы.
     Для начала надо описать необходимые переменные и открыть файл с                       Функция WriteFile возвращает значение TRUE, если операция за-
разрешением асинхронных операций (FILE_FLAG_OVERLAPPED):                                   писи завершена синхронно, а в случае ошибки или начатой
                                                                                           асинхронной операции она возвращает FALSE, поэтому требует-
      OVERLAPPED ov;                                                                       ся анализ кода возникшей «ошибки», которая может и не яв-
      DWORD      dwWritten;                                                                ляться ошибкой.
      BYTE       buffer[ 5000000 ];                                                     2. Выполнение асинхронных операций с ожиданием на объектах
                                                                                           ядра:
      HANDLE fh = CreateFile(
         “file.dat”, FILE_READ_DATA|FILE_WRITE_DATA,                                  ov.Offset = 12345;
         FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL, OPEN_ALWAYS,                   ov.hEvent = CreateEvent((LPSECURITY_ATTRIBUTES)NULL, TRUE, FALSE, 0);
         FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL
      );                                                                              if (
      if ( fh == INVALID_HANDLE_VALUE ) {                                               WriteFile( fh, buffer, sizeof(buffer), &dwWritten, &ov ) ||
         /* возникла ошибка */                                                          GetLastError() == ERROR_IO_PENDING
      }                                                                               ) {
                                                                                        /* пока операция ввода-вывода выполняется, выполняем некоторые
      ZeroMemory( &ov, sizeof(OVERLAPPED) );                                                операции...
      FillMemory( buffer, sizeof(buffer), 123 );                                            дожидаемся завершения операции ввода-вывода */
                                                                                        GetOverlappedResult( fh, &ov, &dwWritten, TRUE );
        1. Выполнение асинхронных операций с опросом состояния; этот                  } else {
           способ может обеспечить самую быструю реакцию на заверше-                    /* возникла ошибка */
           ние операции ввода-вывода, но ценой более высокой загрузки                 }
           процессора:                                                                     Функция GetOverlappedResult в данном случае проверяет состо-
                                                                                           яние операции и, если она еще не завершена, вызывает функ-
      ov.Offset = 12345;                                                                   цию WaitForSingleObject для ожидания завершения операции
      if (                                                                                 ввода-вывода. Объект «событие» можно не создавать – в этом
        WriteFile( fh, buffer, sizeof(buffer), &dwWritten, &ov ) ||                        случае функция будет ожидать освобождения объекта «файл»;
        GetLastError() == ERROR_IO_PENDING                                                 однако в случае нескольких, накладывающихся друг на друга,
      ) {                                                                                  асинхронных операций будет непонятно, какая именно опера-
        /* пока операция ввода-вывода выполняется,                                         ция завершилась, и использование специфичных для каждой
           выполняем некоторые операции.                                                   операции событий снимает эту проблему.
           дожидаемся завершения операции ввода-вывода */                                  Ожидание на объектах ядра является наиболее экономным, но
        while (!GetOverlappedResult(fh, &ov, &dwWritten, FALSE)){}                         реакция приложения на завершение ввода-вывода связана с ра-
      } else {                                                                             ботой планировщика, поэтому для достижения малых задержек
        /* возникла ошибка */                                                              иногда надо дополнительно повышать приоритеты потоков, пе-
      }                                                                                    реходящих в режим ожидания завершения ввода-вывода.
           Функция GetOverlappedResult в данном случае проверяет состоя-                3. Выполнение асинхронных операций с использованием функ-
           ние операции ввода-вывода и возвращает признак ее завершения.                   ций завершения операций ввода-вывода. Эта функция будет ав-
           Опрос состояния операции в цикле позволяет наиболее быстро                      томатически вызвана после завершения ввода-вывода и может