[뇌를 자극하는 윈도우즈 시스템 프로그래밍] 19장 비동기 IO와 APC
https://www.hanbit.co.kr/store/books/look.php?p_code=B7673779595
뇌를 자극하는 윈도우즈 시스템 프로그래밍
이 책은 거의 모든 개발자가 궁금해 하면서도 또한 상당히 어려워하는 컴퓨터 구조, 운영체제, 시스템 프로그래밍의 내용 중 꼭 필요한 부분만 간추려서 담았다. 컴퓨터 구조와 운영체제에 대한
www.hanbit.co.kr
해당 책을 읽고 나름대로 정리한 글입니다.
비동기 IO
동기 IO는 수신 후 처리 수신 후 처리를 blocking 함수를 통해 반복한다.
다만 IO작업은 해당 작업을 기다리는 동안 CPU의 사용률이 낮아진다.
또한 네트워크 작업이 동반되면 이러한 상황은 더 두드러진다.
비동기 IO를 사용하면 데이터를 수신하면서 사운드를 플레이하는 동시에 여러 작업을 할 수 있다.
물론 비동기 IO(엄밀히는 Overlapped IO)를 사용하기 위해서는 기본적으로 논블로킹 함수를 사용해야 한다.
Overlapped(중첩) I/O 예제
중첩 IO 기반 파이프 통신
1단계: 파이프 생성 시 FILE_FLAG_OVERLAPPED를 인자로 전달해서 비동기 특성을 부여한다.
2단계: OVERLAPPED 구조체 변수를 선언한다. 구조체의 hEvent멤버가 가리키는 이벤트 오브젝트를 통해 입출력 연산의 완료를 확인할 수 있다.
3단계: 1단계의 인자를 활용해 생성된 파이프와 OVERLAPPED 구조체를 인자로 전달해 WriteFile, ReadFile을 호출한다.
완료루틴(Completion Routine)기반 확장 I/O
만약 IO A가 완료된 후에는 Routine D, B가 완료된 후에는 Routine E, C가 완료된 후에는 Routine F
가 실행되어야 한다면 완료된 I/O가 무엇인지 구분해서 직접 매핑해야 할 것이다.
Completion Routine(APC = Asynchronous Procedure Call)
다만 Completion Routine기반 확장 IO를 사용하면 이전의 Overlapped IO에 추가적으로 해당 IO가 완료되었을 때 실행할 완료 루틴을 지정할 수 있다.
이를 위해 WriteFile, ReadFile -> WriteFileEx, ReadFileEx함수를 사용한다.
https://learn.microsoft.com/ko-kr/windows/win32/api/fileapi/nf-fileapi-writefileex
WriteFileEx 함수(fileapi.h) - Win32 apps
지정된 파일 또는 I/O(입출력) 디바이스에 데이터를 씁니다. 쓰기가 완료 또는 취소되고 호출 스레드가 경고 대기 상태에 있을 때 완료 상태를 비동기적으로 보고하고, 지정된 완료 루틴을 호출
learn.microsoft.com
BOOL WriteFileEx(
[in] HANDLE hFile,
[in, optional] LPCVOID lpBuffer,
[in] DWORD nNumberOfBytesToWrite,
[in, out] LPOVERLAPPED lpOverlapped,
[in] LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);
WriteFileEx는 이전과 같이 overlapped구조체를 사용하지만 completion routine을 사용하기 때문에 구조체의 hevent가 무시된다.
Alertable State
https://learn.microsoft.com/ko-kr/windows/win32/api/synchapi/nf-synchapi-sleepex
SleepEx 함수(synchapi.h) - Win32 apps
지정된 조건이 충족될 때까지 현재 스레드를 일시 중단합니다.
learn.microsoft.com
SleepEx는 두번째인자로 bAlertable을 받는다.
만약 FALSE라면 일반적인 Sleep과 동일하며, TRUE라면 Sleep이 깨어나는 조건에 Alertable도 들어간다.
APC Queue에 실행할 Completion routine이 있다면 alertable state가 되고 콜백을 실행한 뒤 WAIT_IO_COMPLETION을 return한다.
alertable state에 들어가지 않으면 Completion Routine은 실행되지 않기 때문에 중첩된 IO연산들이 끝나고 Completion Routine을 실행하고 싶다면 alertable state가 되지 않게 해야한다.
OVERLAPPED 구조체의 파일 위치 정보
파일 포인터의 경우 writefile을 사용했을 때 해당 입출력이 연산 시 파일 포인터가 뒤로 이동한다.
다만 중첩 IO에서는 IO가 비동기적으로 진행되기 때문에 overlapped mode에서 입출력을 진행하면 파일 포인터가 갱신되지 않은채 파일 입출력을 하게 된다.
결론적으로 비동기 IO에서 커널 오브젝트에 존재하는 파일 위치 정보는 의미가 없다.
따라서 이러한 작업을 하기 위해서는 프로그래머가 직접 계산해서 OVERLAPPED 구조체의 Offset멤버의 값을 바꿔준다.
APC(Asynchronous Procedure Call)
APC는 User mode APC와 Kernel mode APC로 나뉜다.
Kernel mode APC는 Normal kernel mode APC와 Special kernel mode APC로 다시 나뉜다.
책에서는 User mode APC만 언급한다.
모든 Thread는 자신의 APC Queue를 지닌다.
queue에는 함수(completion routine)포인터와 parameter 정보가 저장된다.
APC Queue에 들어간 함수는 Thread가 Alertable state에 진입하면 호출된다.
QueueUserAPC 함수(processthreadsapi.h) - Win32 apps
지정된 스레드의 APC 큐에 APC(사용자 모드 비동기 프로시저 호출) 개체를 추가합니다. (QueueUserAPC)
learn.microsoft.com
QueueUserAPC함수를 사용하면 직접적으로 Queue에 함수 정보를 전달할 수 있다.