이번 포스팅은 '소켓 프로그래밍' 이라는 과목을 수강하면서 배운 내용 중 'Overlapped IO와 IOCP 관계'라는 주제로 글을 작성해 보려고 합니다.
기본적으로 I/O 작업은 동기로 이루어집니다. 예를 들어 ReadFile(파일을 읽어들이는 메서드)함수를 호출 시 읽기 작업이 끝나기 전까지 함수는 값을 반환하지 않고 처리를 기다리게 됩니다. 즉, 동기적으로 I/O를 처리합니다.
이렇게 해당 스레드에서 작업이 끝날 때 까지 다른 작업을 수행하지 못하고 대기 해야하는 상태를 Blocking 모드라고 합니다.
그럼 Non-Blocking 모드는 반대되는 개념이겠죠? 예상 대로 Non-Blocking모드는 I/O 작업을 호출하고 바로 반환되기에 해당 스레드는 I/O 작업을 대기하지 않고 다른 작업을 수행할 수 있습니다.
Overlapped IO를 이해하기 위해 Non-Blocking 모드에 대해 설명이 길어졌습니다. 그럼 이제 Overlapped IO의 동작 방식을 정리하면서 개념을 구체적으로 이해해보겠습니다.
다음은 I/O작업을 비동기로 처리하는 동작 과정에 대해 정리했다. (사실 Overlapped I/O, IOCP모두 비동기 방식으로 I/O를 처리하는 방법이기에 4번의 과정 이후에 어떻게 I/O의 처리가 끝났음을 확인하는지의 차이만 있을 뿐이다.)
4번까지의 과정을 요약하면 I/O처리 요청을 스레드가 디바이스 드라이버에 위임하고 I/O작업이 종료될때까지 해당 스레드는 다른 작업을 수행할 수 있도록 하는 것이 핵심이다.
핵심은 5번의 과정이다. 5번의 과정은 '어떻게 I/O의 완료 여부를 확인할 것인가?'이다.
1. Overlapped IO 방식
이 방식은 IO를 요청한 스레드에서 처리하는 방법으로 해당 스레드가 IO의 작업이 완료 되었는지 계속 확인해야 한다는 단점이 있다.
단점에 대해 좀더 자세히 알아보자.
해당 스레드는 WSAWaitForMultipleEvents 함수를 호출하여 스레드를 정지시키고 알림을 수신할 때까지 기다리는 방식을 사용할 경우 스레드 실행이 정지되고 다른 스레드에게 실행 기회를 양도하게 된다. 이럴 경우 비동기 처리의 장점을 효과적으로 사용할 수 없으며 성능이 저하되는 문제도 발생한다.
💡 정리하자면, Overlapped IO는 I/O작업이 종료 될 때까지 해당 스레드는 I/O 작업이 완료됬는지 확인하고 I/O 완료되면 이후의 처리를 진행한다. 즉, I/O를 요청한 스레드에서 I/O 완료 확인과 후처리를 진행하는 것이다.
IOCP는 이 완료 확인과 후처리를 쓰레드를 새로 생성해 처리한다. IOCP 작업에 대해 자세히 확인해보자.
2. IOCP 방식
1. 완료 포트(Completion Port) 생성
여기서 완료 포트(Completion Port, 이후로는 CP로 부르겠다.)는 IO 작업의 완료 알림을 받을 수 있는 커널 오브젝트이다.
2. IO 객체와 CP 객체 연결
IO 객체(일반적으로 네트워크 소켓이나 파일 핸들)을 생성하고 CreationIOPort함수를 사용해 해당 IO객체를 CP와 연결한다. 이렇게 하면 IO작업의 완료 알림을 받을 수 있다.
3. 비동기 IO 작업의 시작
이때 IO 작업이 완료되면 해당 작업에 대한 결과와 함께 CP 객체로 알림이 온다.
4. 작업자 스레드 생성
일반적으로 스레드 풀을 사용해 작업자 스레드를 생성한다. (스레드는 개발자가 직접 생성해야한다.) 작업자 스레드는 CP에서 알림을 받아 IO 작업을 처리한다.
5. 작업자 스레드 대기
작업자 스레드는 GetQueuedCompltionStatus함수를 사용해 CP에서 알림을 기다린다. 이 함수는 IO작업을 처리하고 필요에 따라 추가 작업을 수행한다.
6. IO 작업 완료 알림 처리
IO 작업이 완료되면 해당 작업의 결과와 함께 완료 포트로 알림이 전달된다. 작업자 스레드는 이 알림을 받아 작업을 처리하고 필요에 따라 추가 작업을 수행한다.

IOCP의 CP에 알림이 등록되면 CP에 등록된 Worker Thread Pool에서 대기중인 쓰레드 하나를 사용해 IO 작업 완료 확인과 결과를 받아 후처리하는 이미지 예시입니다.
정리하자면 IOCP는 작업자 스레드가 완료포트의 알림을 받아 비동기 작업을 처리하는 방식으로 동작합니다. 이를 통해 다수의 IO 작업을 효율적으로 처리할 수 있습니다. IOCP는 멀티 쓰레드 환경에서 비동기 작업을 효율적으로 처리할 수 있습니다.
이번 글에서는 Overlapped IO와 IOCP에 대해 정리해 봤습니다. (시험 기간은 언제나 다른걸 할 때 재밌는것 같아요..ㅎㅎ)