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

UptoLike

мощью функции PostQueuedCompletionStatus надо будет поме-
щать в очередь порта запросы, имитирующие завершение ввода-
вывода.
Рассмотрим небольшой пример (проверка ошибок для упрощения
пропущена):
#include <process.h>
#define _WIN32_WINNT 0x0500
#include <windows.h>
#define MAXQUERIES 15
#define CONCURENTS 3
#define POOLSIZE 5
unsigned __stdcall PoolProc( void *arg );
int main( void )
{
int i;
HANDLE hcport, hthread[ POOLSIZE ];
DWORD temp;
/* создаем порт завершения ввода-вывода */
hcport = CreateIoCompletionPort(
INVALID_HANDLE_VALUE, NULL, NULL, CONCURENTS
);
После создания порта надо создать пул потоков. Число потоков в пу-
ле обычно превышает число одновременно работающих потоков, задавае-
мое при создании порта:
/* создаем пул потоков */
for ( i = 0; i < POOLSIZE; i++ ) {
hthread[i] = (HANDLE)_beginthreadex(
NULL,0,PoolProc,(void*)hcport,0,(unsigned*)&temp
);
}
Если созданный порт ассоциирован с одним или несколькими файла-
ми, то после завершения асинхронных операций ввода-вывода в очереди
порта будут размещаться асинхронные запросы, которые система будет на-
правлять для обработки потокам из пула. Однако порт завершения ввода-вы-
вода можно и не связывать с файлами – тогда для размещения запроса мож-
но воспользоваться функцией PostQueuedCompletionStatus, которая размеща-
ет запросы в очереди без выполнения реальных операций ввода-вывода.
Разработка параллельных приложений для ОС Windows
221
Эта функция выполняет две разных операции – во-первых, она соз-
дает новый порт завершения, и, во-вторых, она ассоциирует порт с завер-
шением операций ввода-вывода с заданным файлом. Обе эти операции
могут быть выполнены одновременно одним вызовом функции, а могут
быть исполнены раздельно. Более того, вторая операция – ассоциирова-
ние порта завершения ввода-вывода с реальным файлом – может вообще
не выполняться. Две типичных формы применения функции
CreateIoCompletionPort:
1. Создание нового порта завершения ввода-вывода:
#define CONCURRENTS 4
HANDLE hCP;
hCP = CreateIoCompletionPort(
INVALID_HANDLE_VALUE, NULL, NULL, CONCURRENTS
);
При простом создании порта завершения ввода-вывода доста-
точно указать только максимальное число одновременно рабо-
тающих потоков (здесь CONCURRENTS, целесообразно ограничи-
вать числом доступных процессоров). Далее, когда будет созда-
ваться пул потоков, в нем можно будет создать и большее число
потоков, чем указано при создании порта – система будет отсле-
живать, чтобы одновременно исполнялся код не более чем ука-
занного числа потоков. При этом поток, перешедший в состоя-
ние ожидания, не считается исполняющимся, так что в случае
потоков, проводящих часть времени в режиме ожидания, имеет
смысл создавать пул потоков большего размера, чем указано
при вызове функции CreateIoCompletionPort.
2. Ассоциирование порта с файлом:
#define SOME_NUMBER 123
CreateIoCompletionPort( hFile, hCP, SOME_NUMBER, 0 );
В этом варианте функция CreateIoCompletionPort не создает но-
вого порта, а возвращает переданный ей описатель уже сущест-
вующего. Существующий порт завершения ввода-вывода мож-
но связать с несколькими различными файлами одновременно;
при этом процедура, обслуживающая завершение ввода-вывода,
сможет различать, операция с каким именно файлом поставила
в очередь данный запрос, с помощью параметра CompletionKey
(здесь SOME_NUMBER), назначаемого разработчиком. Созданный
порт можно не ассоциировать ни с одним файлом – тогда с по-
220
CIL и системное программирование в Microsoft .NET
220                         CIL и системное программирование в Microsoft .NET   Разработка параллельных приложений для ОС Windows                    221


     Эта функция выполняет две разных операции – во-первых, она соз-                    мощью функции PostQueuedCompletionStatus надо будет поме-
дает новый порт завершения, и, во-вторых, она ассоциирует порт с завер-                 щать в очередь порта запросы, имитирующие завершение ввода-
шением операций ввода-вывода с заданным файлом. Обе эти операции                        вывода.
могут быть выполнены одновременно одним вызовом функции, а могут                    Рассмотрим небольшой пример (проверка ошибок для упрощения
быть исполнены раздельно. Более того, вторая операция – ассоциирова-            пропущена):
ние порта завершения ввода-вывода с реальным файлом – может вообще
не выполняться. Две типичных формы применения функции                                #include 
CreateIoCompletionPort:                                                              #define _WIN32_WINNT 0x0500
       1. Создание нового порта завершения ввода-вывода:                             #include 

         #define CONCURRENTS   4                                                     #define MAXQUERIES 15
                                                                                     #define CONCURENTS 3
          HANDLE    hCP;                                                             #define POOLSIZE   5
          hCP = CreateIoCompletionPort(
             INVALID_HANDLE_VALUE, NULL, NULL, CONCURRENTS                           unsigned __stdcall PoolProc( void *arg );
          );
          При простом создании порта завершения ввода-вывода доста-                  int main( void )
          точно указать только максимальное число одновременно рабо-                 {
          тающих потоков (здесь CONCURRENTS, целесообразно ограничи-                   int      i;
          вать числом доступных процессоров). Далее, когда будет созда-                HANDLE hcport, hthread[ POOLSIZE ];
          ваться пул потоков, в нем можно будет создать и большее число                DWORD    temp;
          потоков, чем указано при создании порта – система будет отсле-               /* создаем порт завершения ввода-вывода */
          живать, чтобы одновременно исполнялся код не более чем ука-                  hcport = CreateIoCompletionPort(
          занного числа потоков. При этом поток, перешедший в состоя-                     INVALID_HANDLE_VALUE, NULL, NULL, CONCURENTS
          ние ожидания, не считается исполняющимся, так что в случае                   );
          потоков, проводящих часть времени в режиме ожидания, имеет                 После создания порта надо создать пул потоков. Число потоков в пу-
          смысл создавать пул потоков большего размера, чем указано             ле обычно превышает число одновременно работающих потоков, задавае-
          при вызове функции CreateIoCompletionPort.                            мое при создании порта:
       2. Ассоциирование порта с файлом:
                                                                                        /* создаем пул потоков */
         #define SOME_NUMBER 123                                                        for ( i = 0; i < POOLSIZE; i++ ) {
         CreateIoCompletionPort( hFile, hCP, SOME_NUMBER, 0 );                            hthread[i] = (HANDLE)_beginthreadex(
                                                                                            NULL,0,PoolProc,(void*)hcport,0,(unsigned*)&temp
         В этом варианте функция CreateIoCompletionPort не создает но-                    );
         вого порта, а возвращает переданный ей описатель уже сущест-                   }
         вующего. Существующий порт завершения ввода-вывода мож-                      Если созданный порт ассоциирован с одним или несколькими файла-
         но связать с несколькими различными файлами одновременно;              ми, то после завершения асинхронных операций ввода-вывода в очереди
         при этом процедура, обслуживающая завершение ввода-вывода,             порта будут размещаться асинхронные запросы, которые система будет на-
         сможет различать, операция с каким именно файлом поставила             правлять для обработки потокам из пула. Однако порт завершения ввода-вы-
         в очередь данный запрос, с помощью параметра CompletionKey             вода можно и не связывать с файлами – тогда для размещения запроса мож-
         (здесь SOME_NUMBER), назначаемого разработчиком. Созданный             но воспользоваться функцией PostQueuedCompletionStatus, которая размеща-
         порт можно не ассоциировать ни с одним файлом – тогда с по-            ет запросы в очереди без выполнения реальных операций ввода-вывода.