시작은 미미하나 끝은 쥬쥬하리라.

Study/Windows System Programming

[Window System Programming] Chapter 19. 비동기 I/O와 APC

코딩뚜벅이 2024. 2. 10. 16:32

4-19 비동기 I/O와 APC

  • I/O와 클럭
  • 비동기 I/O
  • 중첩 I/O
  • 완료 루틴 기반 I/O
  • 알람 가능한 상태(Alertable State) & APC(Asynchronous Procedure Call)

 


I/O와 클럭

 

 

ex) 1초에 100번의 연산(100클럭)을 하는 A시스템과 1초에 200번의 연산(200클럭)을 하는 B시스템이 있는 경우

-> 100클럭의 연산데이터를 버퍼를 통해 전송하고 버퍼는 10 클럭마다 비워진다고(전송된다고) 가정

-> A 시스템은 연산에 1초가 소요되며 데이터를 10개로 분할하여 전송

-> B 시스템은 연산에 0.5초가 소요되며 데이터를 20개로 분할하여 전송

-> 일반적으로는 B 시스템(클럭이 높은)이 더 빨라 보이나, 이는 핸드 쉐이크 등 과정이 2배로 사용되는 것을 의미

 

클럭이 빠른 시스템 != 데이터를 전송하는 속도가 빠른 시스템

-> 오히려 클럭이 높아도 더 늘릴 수 있음

-> I/O 연산에서 클럭이 차지하는 영향력은 미비

-> 사용자가 직접 설계 가능한 '버퍼를 비우는 정책'이 데이터 전송에 직접적인 영향

 


 

비동기 I/O

ex) Write 함수가 호출되는 순간 데이터가 전송되고, 함수가 반환되는 순간 데이터 전송이 마무리된다고 가정

 

동기 I/O 모델

 

 

동기 모델의 경우 함수의 호출과 데이터의 전송이 동기화

-> 함수의 반환과 데이터 전송의 끝이 동기화되어 있는 모델

-> Write 함수를 호출하고 데이터 전송이 완료되기 이전까지 함수가 반환되지 않음

-> 함수 반환 전까지 다른 작업 불가 = CPU가 Blocking 상태에 있음

-> 상기 사진 상 CPU 사용률이 0%에 수렴했을 때가 함수 호출 후 반환 이전(Block 상태)인 경우

 

 

비동기 I/O 모델

 

 

비동기 모델은 Write 함수 호출 순간에 데이터가 전송되지만 반환 시점이 데이터 전송의 끝을 의미하지 않음

-> Write 함수 호출과 동시에 반환이 이루어지고 내부적으로 데이터 전송을 수행

-> Write 함수가 반환되었기에 I/O 연산 도중에도 다른 작업 수행 가능

-> 상기 사진을 확인하면 동기 모델에 비해 CPU 사용률이 어느 정도 일정한 모습(병렬적으로 작업 처리)

 

 

중첩 I/O 모델

 

 

I/O 함수를 호출하고 반환하기 이전에 다른 I/O 함수를 호출하여 호출을 중첩하는 방식

-> CPU는 I/O를 수행할 때 느리고, 대기하는 시간도 있기 때문에 중첩하여 대기하는 시간을 줄일 수 있음

 

 

완료 루틴 기반 I/O 모델

 

 

I/O 연산이 완료되고 추후 작업을 진행하기 위해서는 I/O 연산이 종료되었는지 확인해야 함

-> 모든 I/O의 완료 여부를 확인하는 것은 시스템 입장에서 부담

-> 완료 루틴 기반 모델은 I/O 연산이 마무리되면 그 이후 루틴을 자동으로 실행할 수 있는 구조

-> 별도의 연산 완료 확인 과정 없이 이후 작업을 수행할 수 있는 장점

 


 

중첩 I/O

중첩 I/O 구조

 

 

1. 리소스 생성 시 FILE_FLAG_OVERLAPPED를  인자로 전달하고 리소스 전달(파일, 파이프 등)

2. OverLapeed 구조체를 통해 비동기 I/O를 진행

3. 연산이 마무리되면 이벤트가 Signaled 상태로 전환

 

 

Overlapped 구조체

 

 

 

WriteFile() & GetOverlappedResult()

 

 

 

WriteFile() : 데이터 전송 수행

GetOverlappedResult() : 전송한 데이터 확인

-> 중첩 I/O는 비동기 I/O이기 때문에 WriteFile() 함수가 반환된 이후라도 전송 직후에 데이터 확인은 불가능

-> 데이터 전송이 실제로 마무리 된 이후 시점부터 해당 함수를 통한 데이터 확인 가능

 


 

완료 루틴 기반 I/O

완료 루틴 기반 I/O 구조

 

 

완료 루틴 기반 I/O = 중첩 I/O를 확장한 개념

-> 중첩 I/O에 사용된 Overlapped 구조체를 초기화해서 사용

-> 중첩 I/O에 완료 루틴 함수를 추가하고 I/O 연산이 마무리 되면 호출되는 함수가 추가되어 연관 관계 구성

-> 완료 루틴 함수가 호출되면 I/O 연산의 종료를 알 수 있기 때문에 Overlapped 구조체의 Event 핸들 필요하지 않음

 

 

완료 루틴 기반 I/O 함수

 

 

WriteFileEx() : 데이터 전송 수행

-> Comlpetion_Routine 인자는 호출 대상이 사용자가 아닌 Window OS

-> 함수를 선언하면 인자를  Windows OS가 전달

FileIOCompletionRoutine() : 연산 완료 루틴 수행

 


 

알람 가능한 상태(Alertable State) & APC(Asynchronous Procedure Call)

알람 가능한 상태

I/O 연산이 완료되면 완료 루틴을 실행해야하는데, 이 루틴의 실행 타이밍과 관련

-> SleepEx() 함수를 호출하여 두번째 인자로 true 를 전달하면 해당 스레드는 알람 가능한 상태로 전환

-> 완료 루틴 실행

 

 

APC

비동기 함수 호출 메커니즘

모든 스레드는 자신만의 APC 큐를 소유

-> APC 큐 : 스레드가 알람 가능한 상태가 되었을 때, 호출할 함수를 모아놓은 큐

-> QueueUserAPC() : APC 큐에 호출하고자 하는 함수의 정보를 전달하는 함수

 

 

 

-> SleepEx() 함수를 통해 특정 스레드를 알람 가능한 상태로 전환(완료 루틴 실행 준비)

-> QueueUserAPC()를 통해 앞선 스레드의 특정 함수(완료 루틴)를 호출