Disconnect = !ReadFile(Key[KeyIndex].hNp, &Key[KeyIndex].Req, RQ_SIZE, &nXfer, &Key[KeyIndex].Ov) && GetLastError () == ERROR_HANDLE_EOF; /* Первая операция чтения. */

   if (Disconnect) continue;

   Success = TRUE;

  } else {

   /* Чтение завершилось. Обработать запрос. */

   ShutDown = ShutDown || (_tcscmp (Key[KeyIndex].Req.Record, ShutRqst) == 0);

   if (ShutDown) continue;

   /* Создать процесс для выполнения команды. */

   /* … */ 

   /* Отвечать по одной строке за один раз. На данном этапе удобно использовать функции библиотеки С для работы со строками. */

   fp = _tfopen(pThArg->TmpFileName, _T("r"));

   Response.Status = 0;

   /* Поскольку младший бит события установлен, ответные сообщения в очередь порта завершения не помещаются. */

   while(_fgetts(Response.Record, MAX_RQRS_LEN, fp) != NULL) {

    WriteFile(Key [KeyIndex].hNp, &Response, RS_SIZE, &nXfer, &ovResp);

    WaitForSingleObject(hWrEvent, INFINITE);

   }

   fclose(fp);

   /* Уничтожить содержимое временного файла. */

   SetFilePointer(hTmpFile, 0, NULL, FILE_BEGIN);

   SetEndOfFile(hTmpFile);

   /* Отправить признак конца ответа. */

   Response.Status = 1;

   strcpy(Response.Record, "");

   WriteFile(Key[KeyIndex].hNp, &Response, RS_SIZE, &nXfer, &ovResp);

   WaitForSingleObject(hWrEvent, INFINITE);

   /* Конец основного командного цикла. Получить следующую команду.*/

   Disconnect = !ReadFile(Key[KeyIndex].hNp, &Key[KeyIndex].Req, RQ_SIZE, &nXfer, &Key[KeyIndex].Ov) && GetLastError() == ERROR_HANDLE_EOF; /* Следующее чтение */

   if (Disconnect) continue;

   Success = TRUE;

  }

 } __finally {

  if (Disconnect) {

   /* Создать еще одно соединение по этому каналу. */

   Key[KeyIndex].Type = 0;

   DisconnectNamedPipe(Key[KeyIndex].hNp);

   ConnectNamedPipe(Key[KeyIndex].hNp, &Key[KeyIndex].Ov);

  }

  if (!Success) {

   ReportError(_T("Ошибка сервера"), 0, TRUE);

   Exit = TRUE;

  }

 }

 FlushFileBuffers(Key[KeyIndex].hNp);

 DisconnectNamedPipe(Key[KeyIndex].hNp);

 CloseHandle(hTmpFile);

 /* … */

 _endthreadex(0);

 return 0;

 /* Подавление предупреждающих сообщений компилятора. */

} 

<p>Резюме</p>

Для выполнения асинхронных операций ввода/вывода в Windows предусмотрены три метода. Самой распространенной и наиболее простой является методика, основанная на использовании потоков, которая, в отличие от двух остальных, способна работать даже под управлением Windows 9x. Каждый из потоков отвечает за выполнение определенной последовательности действий, состоящей из одной или нескольких последовательно выполняющихся, блокирующихся операций ввода/вывода. Кроме того, каждый поток должен располагать собственным дескриптором файла или канала.

Перекрывающийся ввод/вывод обеспечивает возможность выполнения асинхронных операций одним потоком с использованием одного дескриптора файла, но каждой отдельной операции вместо пары "поток—дескриптор файла" должен предоставляться дескриптор события. При этом требуется организовать ожидание завершения выполнения каждой конкретной операции ввода/вывода по отдельности, а затем очищать системные ресурсы или выполнять любые другие действия, необходимые для управления последовательностью выполнения операций.

Перейти на страницу:

Похожие книги