카테고리 없음
[TIL] Blocking, Non-Blocking I/O
s00ng
2025. 3. 3. 08:10
Blocking I/O
I/O 작업을 요청한 프로세스/스레드는 요청이 완료될때까지 차단(Block) 됨
- 하나의 Thread에서 Blocking으로 동작하는 read system call을 호출한다.
- OS Kernel로 전환하기위해 Context-switching이 발생한다
- Kernel에서는 read I/O를 실행하여 외부 소켓과 connection을 맺는다. (TCP 기준)
- 외부 소켓으로부터 데이터를 읽어, Kernel space에서 User space(Application)로 데이터를 전달한다.
- OS Kernel로부터 데이터를 전달받은 Thread는 그제서야 다른 작업을 처리한다.
+) Socket에게 Block I/O란?
- socket A는 네트워크상에서 Data를 읽는 주체, socket S는 Data를 쓰는 주체이다.
- socket A에 read system call을 호출한 Thread는 recv_buffer에 데이터를 읽을 때까지 Block 된다.
- socket S에 write system call을 호출한 Thread는 send_buffer의 여유공간이 생길때까지 Block 된다.
- send_buffer의 저장공간이 가득 차있다면 데이터를 Buffer로 쓰는 동작 방식에서는 데이터를 쓸 수 없기 때문에 Buffer에 여유 공간이 생길때까지 Block 되는 것이다.
Non-Blocking I/O
I/O 작업을 처리하는동안 스레드가 다른 작업을 수행할 수 있다
프로세스/스레드를 Block 시키지 않고 요청에 대한 현재 상태를 즉시 리턴하여 I/O 작업을 처리하는 도중에 다른 작업을 처리할 수 있도록 동작하는 방식
- 하나의 Thread에서 Non-blocking으로 동작하는 read system call을 호출
- OS Kernel로 전환하기위해 Context-switching이 발생한다
- OS Kernel에서는 아직 데이터가 준비되지 않았음을 표현하는 -1값과 EAGAIN같은 Error code를 Thread로 즉시 리턴한다.
- Thread는 Block 되지 않고 다른 작업을 수행한다
- 외부 소켓으로부터 수신한 데이터는 OS Kernel에 적재되며 데이터를 준비한다.
- Thread는 다시 read system call을 호출한다.
- 이제는 OS Kernel level에서 데이터가 준비되어있기 때문에 data를 OS Kernel에서 User space로 전달한다.
+) Socket에게 Non-Block I/O란?
- Blocking I/O에서는 read system call이 호출되면 recv_buffer에서 데이터를 읽을때까지 대기, Block 되었다.
- 하지만 Non-Blocking I/O에서는 read system call이 호출되면 recv_buffer에 데이터가 준비되었다면 바로 읽고, 데이터가 없다면 데이터가 없음을 바로 return한다. 즉, Block 되지 않는다.
- Socket을 통해 데이터를 송신하는 입장에서도 send_buffer가 가득차있다면 send_buffer에 여유공간이 생길때까지 기다리지 않고 적절한 에러코드와 함께 return하여 Block되지 않게끔 동작한다.
I/O 작업 완료를 확인하는 방법
1. 완료되었는지 반복적으로 확인
- read system call을 non-blocking 으로 호출
- buffer에 데이터가 준비되지 않았다면 -1과 에러코드 반환
- 다른 작업을 수행하다 다시 read system call 호출
- 데이터가 준비될때까지 반복
문제
- 완료된 시간과 Thread가 작업 완료를 확인한 시간 사이의 Gap이 존재하여 처리 속도가 느려질 수 있음
- 작업이 완료되었는지 반복적으로 확인하는 작업 자체가 CPU를 낭비하는 행위
2. I/O Multiplexing (다중 입출력)
- 관심있는 I/O 작업들을 동시에 모니터링하고 그 중에 완료된 작업들을 한 번에 알려주는 방식
- 네트워크 통신에 많이 사용됨
- I/O Multiplexing system call을 호출하여 2개의 socket을 모니터링한다.
- OS Kernel에서는 2개의 Socket을 통해 Read I/O 작업을 수행
- system call을 호출한 Thread는 여러 형태가 가능 (Blocked 또는 Non-Blocked)
- socket에 데이터가 준비되면 OS Kernel 레벨에서 데이터가 준비되었음을 notify 해줌
- 데이터가 준비되었음을 알게된 Thread는 Socket으로부터 Buffer에 적재된 데이터를 읽어와서 처리