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

UptoLike

6.2.2. Асинхронные вызовы процедур
Для реализации асинхронного ввода-вывода в операционной систе-
ме предусмотрен специальный механизм, основанный на так называемых
асинхронных вызовах процедур (Аsynchronous Procedure Call, APC). Это один
из базовых механизмов, необходимый для нормального функционирова-
ния операционной системы.
Практика показала, что такой механизм был бы эффективен и для ре-
ализации самих приложений. Более того, для реализации асинхронного
ввода-вывода с поддержкой функции завершения система уже обязана
была предоставить этот механизм. Для реализации этого механизма опе-
рационная система ведет списки процедур, которые она должна вызывать
в контексте данного потока, с тем ограничением, что прерывать работу за-
нятого потока в произвольный момент времени система не должна. Поэ-
тому для обслуживания накопившихся в очереди процедур необходимо
перевести поток в специальное состояние ожидания оповещения (alertable
waiting)– для этого Win32 API предусматривает специальный набор функ-
ций: например, SleepEx, WaitForSingleObjectEx и др.
Здесь и во многих примерах далее, чтобы не загромождать код приме-
ра, опущена проверка ошибок:
VOID CALLBACK ApcProc( ULONG_PTR dwData )
{
/* ... */
}
int main( void )
{
QueueUserAPC( ApcProc, GetCurrentThread(), 0 );
/* ... */
SleepEx( 1000, TRUE );
return 0;
}
Обычно APC используются самой системой для реализации асин-
хронного ввода-вывода и некоторых других операций, но разработчикам
также предоставлена функция QueueUserAPC, с помощью которой можно
ставить в APC очередь запросы для вызова собственных функций.
6.2.3. Процессы, потоки и объекты ядра
Обсуждение реализации мультипрограммирования в операционной
системе неизбежно приводит к обсуждению вопросов безопасности.
В мультипрограммной среде может одновременно выполняться значи-
тельное количество процессов, представляющих разных пользователей, и
Основы многозадачности
207
выполнить некоторые специальные действия. Процедура завер-
шения обязательно вызывается в контексте того потока, кото-
рый вызвал операцию ввода-вывода, – а для этого необходимо,
чтобы поток был приостановлен, так как операционная система
не должна прерывать работу активного потока. Следует переве-
сти поток в состояние ожидания оповещения (alertable waiting) –
при этом он не выполняется и может быть прерван для обработ-
ки процедуры завершения:
ov.Offset = 12345;
if ( WriteFileEx( fh, buffer, sizeof(buffer), &ov, io_done ) ) {
/* пока операция ввода-вывода выполняется, выполняем некоторые
операции и переходим в режим ожидания оповещения,
например, так: */
if ( SleepEx( INFINITE, TRUE ) != WAIT_IO_COMPLETION ) {
/* ввод-вывод пока не завершен, возможно, ошибка */
}
} else {
/* возникла ошибка */
}
/* нам еще надо предоставить собственную процедуру
завершения ввода-вывода. В простейшем варианте
она может ничего не делать: */
VOID CALLBACK io_done(
DWORD dwErr, DWORD dwWritten, LPOVERLAPPED lpOv
) {
...
}
Этот подход наиболее трудоемок и наименее распространен; на
практике самым эффективным является механизм выполнения
асинхронных операций с ожиданием на объектах ядра. Однако
механизм вызова функций завершения (расширенный возмож-
ностью автоматического выбора потока, осуществляющего об-
работку функции завершения) послужил основой для реализа-
ции одного из очень эффективных механизмов взаимодействия
потоков – порта завершения ввода-вывода.
При использовании асинхронного ввода-вывода необходимо очень
внимательно следить за выделением и освобождением ресурсов – особен-
но памяти, занятой структурами OVERLAPPED, и буферами, участвующими в
операциях ввода-вывода.
Асинхронный ввод-вывод является примером мультипроцессирова-
ния с использованием функционально различных устройств.
206
CIL и системное программирование в Microsoft .NET
206                        CIL и системное программирование в Microsoft .NET   Основы многозадачности                                               207


         выполнить некоторые специальные действия. Процедура завер-            6.2.2. Асинхронные вызовы процедур
         шения обязательно вызывается в контексте того потока, кото-
         рый вызвал операцию ввода-вывода, – а для этого необходимо,                 Для реализации асинхронного ввода-вывода в операционной систе-
         чтобы поток был приостановлен, так как операционная система           ме предусмотрен специальный механизм, основанный на так называемых
         не должна прерывать работу активного потока. Следует переве-          асинхронных вызовах процедур (Аsynchronous Procedure Call, APC). Это один
         сти поток в состояние ожидания оповещения (alertable waiting) –       из базовых механизмов, необходимый для нормального функционирова-
         при этом он не выполняется и может быть прерван для обработ-          ния операционной системы.
         ки процедуры завершения:                                                    Практика показала, что такой механизм был бы эффективен и для ре-
                                                                               ализации самих приложений. Более того, для реализации асинхронного
     ov.Offset = 12345;                                                        ввода-вывода с поддержкой функции завершения система уже обязана
     if ( WriteFileEx( fh, buffer, sizeof(buffer), &ov, io_done ) ) {          была предоставить этот механизм. Для реализации этого механизма опе-
       /* пока операция ввода-вывода выполняется, выполняем некоторые          рационная система ведет списки процедур, которые она должна вызывать
          операции и переходим в режим ожидания оповещения,                    в контексте данного потока, с тем ограничением, что прерывать работу за-
          например, так: */                                                    нятого потока в произвольный момент времени система не должна. Поэ-
       if ( SleepEx( INFINITE, TRUE ) != WAIT_IO_COMPLETION ) {                тому для обслуживания накопившихся в очереди процедур необходимо
         /* ввод-вывод пока не завершен, возможно, ошибка */                   перевести поток в специальное состояние ожидания оповещения (alertable
       }                                                                       waiting) – для этого Win32 API предусматривает специальный набор функ-
     } else {                                                                  ций: например, SleepEx, WaitForSingleObjectEx и др.
         /* возникла ошибка */                                                       Здесь и во многих примерах далее, чтобы не загромождать код приме-
     }                                                                         ра, опущена проверка ошибок:
     /* нам еще надо предоставить собственную процедуру
         завершения ввода-вывода. В простейшем варианте                             VOID CALLBACK ApcProc( ULONG_PTR dwData )
         она может ничего не делать: */                                             {
     VOID CALLBACK io_done(                                                           /* ... */
       DWORD dwErr, DWORD dwWritten, LPOVERLAPPED lpOv                              }
     ) {                                                                            int main( void )
       ...                                                                          {
     }                                                                                QueueUserAPC( ApcProc, GetCurrentThread(), 0 );
          Этот подход наиболее трудоемок и наименее распространен; на                 /* ... */
          практике самым эффективным является механизм выполнения                     SleepEx( 1000, TRUE );
          асинхронных операций с ожиданием на объектах ядра. Однако                   return 0;
          механизм вызова функций завершения (расширенный возмож-                   }
          ностью автоматического выбора потока, осуществляющего об-                 Обычно APC используются самой системой для реализации асин-
          работку функции завершения) послужил основой для реализа-            хронного ввода-вывода и некоторых других операций, но разработчикам
          ции одного из очень эффективных механизмов взаимодействия            также предоставлена функция QueueUserAPC, с помощью которой можно
          потоков – порта завершения ввода-вывода.                             ставить в APC очередь запросы для вызова собственных функций.
     При использовании асинхронного ввода-вывода необходимо очень
внимательно следить за выделением и освобождением ресурсов – особен-           6.2.3. Процессы, потоки и объекты ядра
но памяти, занятой структурами OVERLAPPED, и буферами, участвующими в               Обсуждение реализации мультипрограммирования в операционной
операциях ввода-вывода.                                                        системе неизбежно приводит к обсуждению вопросов безопасности.
     Асинхронный ввод-вывод является примером мультипроцессирова-              В мультипрограммной среде может одновременно выполняться значи-
ния с использованием функционально различных устройств.                        тельное количество процессов, представляющих разных пользователей, и