I/O 완료 포트
I/O 완성 포트는 다중 프로세서 시스템에서 여러 비동기 I/O 요청을 처리하기 위한 효율적인 스레딩 모델을 제공합니다. 프로세스에서 I/O 완료 포트를 만들 때 시스템은 이러한 요청을 처리하는 것이 유일한 용도인 스레드에 연결된 큐 개체를 만듭니다. 많은 동시 비동기 I/O 요청을 처리하는 프로세스는 I/O 요청을 수신할 때 스레드를 만드는 것보다 미리 할당된 스레드 풀과 함께 I/O 완료 포트를 사용하여 더 빠르고 효율적으로 수행할 수 있습니다.
I/O 완료 포트 작동 방식
CreateIoCompletionPort 함수는 I/O 완성 포트를 만들고 하나 이상의 파일 핸들을 해당 포트와 연결합니다. 이러한 파일 핸들 중 하나에 대한 비동기 I/O 작업이 완료되면 I/O 완료 패킷이 연결된 I/O 완료 포트에 대한 FIFO(선착순) 순서로 큐에 대기됩니다. 이 메커니즘의 한 가지 강력한 용도는 여러 파일 핸들의 동기화 지점을 단일 개체로 결합하는 것이지만 다른 유용한 애플리케이션도 있습니다. 패킷은 FIFO 순서로 큐에 대기하는 동안 다른 순서로 큐에서 제거될 수 있습니다.
메모
여기서 사용되는 파일 핸들 용어는 디스크의 파일뿐만 아니라 겹치는 I/O 엔드포인트를 나타내는 시스템 추상화입니다. 예를 들어 네트워크 엔드포인트, TCP 소켓, 명명된 파이프 또는 메일 슬롯일 수 있습니다. 겹치는 I/O를 지원하는 모든 시스템 개체를 사용할 수 있습니다. 관련 I/O 함수 목록은 이 항목의 끝을 참조하세요.
파일 핸들이 완료 포트와 연결된 경우 전달된 상태 블록은 완료 포트에서 패킷이 제거될 때까지 업데이트되지 않습니다. 유일한 예외는 원래 작업이 오류와 함께 동기적으로 반환되는 경우입니다. 스레드(주 스레드 또는 주 스레드 자체에서 만든 스레드)는 GetQueuedCompletionStatus 함수를 사용하여 비동기 I/O가 완료될 때까지 직접 기다리지 않고 완료 패킷이 I/O 완료 포트에 큐에 대기할 때까지 기다립니다. I/O 완료 포트에서 실행을 차단하는 스레드는 LIFO(Last-in-first-out) 순서로 해제되고, 다음 완료 패킷은 해당 스레드에 대한 I/O 완료 포트의 FIFO 큐에서 가져옵니다. 즉, 완료 패킷이 스레드에 릴리스되면 시스템은 해당 포트와 연결된 마지막(가장 최근) 스레드를 해제하고 가장 오래된 I/O 완료에 대한 완료 정보를 전달합니다.
지정된 I/O 완료 포트에 대해 GetQueuedCompletionStatus 호출할 수 있는 스레드 수는 있지만 지정된 스레드가 처음으로 GetQueuedCompletionStatus를 호출할 때는 세 가지 중 하나가 발생할 때까지 지정된 I/O 완료 포트와 연결됩니다. 스레드가 종료되고 다른 I/O 완료 포트를 지정합니다. 또는 I/O 완료 포트를 닫습니다. 즉, 단일 스레드는 최대 하나의 I/O 완료 포트와 연결될 수 있습니다.
완료 패킷이 I/O 완료 포트에 큐에 대기하는 경우 시스템은 먼저 해당 포트와 연결된 스레드 수를 확인합니다. 실행 중인 스레드 수가 동시성 값(다음 섹션에서 설명)보다 작으면 대기 중인 스레드(가장 최근 스레드) 중 하나가 완료 패킷을 처리할 수 있습니다. 실행 중인 스레드가 처리를 완료하면 일반적으로 GetQueuedCompletionStatus호출하며, 이때 다음 완료 패킷으로 반환되거나 큐가 비어 있는 경우 대기합니다.
스레드는 PostQueuedCompletionStatus 함수를 사용하여 I/O 완료 포트의 큐에 완료 패킷을 배치할 수 있습니다. 이렇게 하면 I/O 시스템에서 I/O 완료 패킷을 수신하는 것 외에도 완료 포트를 사용하여 프로세스의 다른 스레드로부터 통신을 수신할 수 있습니다. PostQueuedCompletionStatus 함수를 사용하면 애플리케이션이 비동기 I/O 작업을 시작하지 않고도 고유한 특수 용도 완료 패킷을 I/O 완료 포트에 큐에 대기할 수 있습니다. 예를 들어 작업자 스레드에 외부 이벤트를 알리는 데 유용합니다.
I/O 완성 포트 핸들 및 해당 특정 I/O 완료 포트와 연결된 모든 파일 핸들을 I/O 완료 포트 대한참조라고 합니다. I/O 완성 포트는 더 이상 참조가 없는 경우 해제됩니다. 따라서 I/O 완성 포트 및 관련 시스템 리소스를 해제하려면 이러한 핸들을 모두 올바르게 닫아야 합니다. 이러한 조건이 충족되면 애플리케이션은 CloseHandle 함수를 호출하여 I/O 완료 포트 핸들을 닫아야 합니다.
메모
I/O 완성 포트는 I/O 완료 포트를 만든 프로세스와 연결되며 프로세스 간에 공유할 수 없습니다. 그러나 단일 핸들은 동일한 프로세스의 스레드 간에 공유할 수 있습니다.
스레드 및 동시성
신중하게 고려해야 할 I/O 완성 포트의 가장 중요한 속성은 동시성 값입니다. 완성 포트의 동시성 값은 NumberOfConcurrentThreads 매개 변수를 통해 CreateIoCompletionPort 사용하여 만들 때 지정됩니다. 이 값은 완료 포트와 연결된 실행 가능한 스레드 수를 제한합니다. 완료 포트와 연결된 실행 가능한 스레드의 총 수가 동시성 값에 도달하면 시스템은 실행 가능한 스레드 수가 동시성 값 아래로 떨어질 때까지 해당 완료 포트와 연결된 후속 스레드의 실행을 차단합니다.
가장 효율적인 시나리오는 큐에서 대기 중인 완료 패킷이 있지만 포트가 동시성 제한에 도달했기 때문에 대기를 충족할 수 없는 경우에 발생합니다. GetQueuedCompletionStatus 함수 호출에서 대기 중인 하나 및 여러 스레드의 동시성 값이 어떻게 고려합니다. 이 경우 큐에 항상 완료 패킷이 대기 중인 경우 실행 중인 스레드가 GetQueuedCompletionStatus 호출할 때 앞에서 설명한 대로 스레드 큐가 LIFO이므로 실행을 차단하지 않습니다. 대신 이 스레드는 대기 중인 다음 완료 패킷을 즉시 선택합니다. 실행 중인 스레드가 계속해서 완료 패킷을 선택하고 다른 스레드를 실행할 수 없으므로 스레드 컨텍스트 전환이 발생하지 않습니다.
메모
이전 예제에서 추가 스레드는 쓸모가 없고 실행되지 않는 것처럼 보이지만 실행 중인 스레드가 다른 메커니즘에 의해 대기 상태로 전환되지 않거나, 종료되거나, 연결된 I/O 완료 포트를 닫지 않는 것으로 가정합니다. 애플리케이션을 디자인할 때 이러한 모든 스레드 실행 파급 효과를 고려합니다.
동시성 값에 대해 선택할 수 있는 가장 좋은 전체 최대값은 컴퓨터의 CPU 수입니다. 트랜잭션에 긴 계산이 필요한 경우 더 큰 동시성 값을 사용하면 더 많은 스레드를 실행할 수 있습니다. 각 완료 패킷을 완료하는 데 시간이 더 오래 걸릴 수 있지만 더 많은 완료 패킷이 동시에 처리됩니다. 프로파일링 도구와 함께 동시성 값을 실험하여 애플리케이션에 최상의 효과를 얻을 수 있습니다.
또한 시스템은 동일한 I/O 완료 포트와 연결된 다른 실행 중인 스레드가 SuspendThread 함수와 같은 다른 이유로 대기 상태로 전환되는 경우 GetQueuedCompletionStatus 대기 중인 스레드가 완료 패킷을 처리할 수 있도록 허용합니다. 대기 상태의 스레드가 다시 실행되기 시작하면 활성 스레드 수가 동시성 값을 초과하는 짧은 기간이 있을 수 있습니다. 그러나 시스템은 활성 스레드 수가 동시성 값 아래로 떨어질 때까지 새 활성 스레드를 허용하지 않음으로써 이 수를 빠르게 줄입니다. 이는 애플리케이션이 동시성 값보다 스레드 풀에 더 많은 스레드를 만들도록 하는 이유 중 하나입니다. 스레드 풀 관리는 이 항목의 범위를 벗어나지만 시스템에 프로세서가 있는 스레드 풀의 스레드 수를 최소 2배 이상 보유하는 것이 좋습니다. 스레드 풀링에 대한 자세한 내용은 스레드 풀참조하세요.
지원되는 I/O 함수
다음 함수를 사용하여 I/O 완료 포트를 사용하여 완료되는 I/O 작업을 시작할 수 있습니다. I/O 완료 포트 메커니즘을 사용하도록 설정하려면 OVERLAPPED 구조의 인스턴스와 I/O 완료 포트와 이전에 연결된 파일 핸들(CreateIoCompletionPort호출)을 전달해야 합니다.
- AcceptEx
- ConnectNamedPipe
- DeviceIoControl
- LockFileEx
- ReadDirectoryChangesW
- ReadFile
- TransactNamedPipe
- WaitCommEvent
- WriteFile
- WSASendMsg
- WSASendTo
- WSASend
- WSARecvFrom
- LPFN_WSARECVMSG(WSARecvMsg)
- WSARecv
관련 항목
-
프로세스 및 스레드 대한