시스템의 Blocking과 Non-Blocking을 이해하기 전에 우선 OS의 System Call Interface에 대한 이해가 필요하다.
System Call Interface
시스템 콜 인터페이스는 프로세스나 스레드로부터 명령을 받는 인터페이스로써 통상적으로 시스템 콜은 여러 종류의 기능으로 나뉘어져 있다. 각 시스템 콜에는 번호가 할당되고 시스템 콜 인터페이스는 이러한 번호에 따라 인덱스 되는 테이블을 유지된다. 아래 그림은 open() 시스템 콜을 호출 했을 때 운영체제에서 어떻게 처리되는지를 보여준다.
**open() 시스템 콜을 호출한 사용자 응용의 처리**
OS Kernel과 System Call Interface 구조
- 운영체제는 커널 모드(Kernel Mode)와 사용자 모드(User Mode)로 나뉘어 구동된다.
- 운영체제에서 프로그램이 구동되는데 있어 파일을 읽어 오거나, 파일을 쓰거나, 혹은 화면에 메시지를 출력하는 등 많은 부분이 커널 모드를 사용한다. 시스템 콜은 이러한 커널 영역의 기능을 사용자 모드가 사용 가능하게, 즉 프로세스가 하드웨어에 직접 접근해서 필요한 기능을 사용할 수 있게 해준다.
필요한 기능이나 시스템 환경에 따라 시스템 콜이 발생할 때 좀 더 많은 정보가 필요할 수 있다. 그러한 정보가 담긴 매개변수를 운영체제에 전달하기 위해서는 대략 3가지 정도의 방법이 있다.
- 매개변수를 CPU 레지스터 내에 전달한다. 이 경우에 매개변수의 갯수가 CPU 내의 총 레지스터 개수보다 많을 수 있다.
- 위와 같은 경우에 매개변수를 메모리에 저장하고 메모리의 주소가 레지스터에 전달된다. (아래 그림 참고)
- 매개변수는 프로그램에 의해 스택(stack)으로 전달(push) 될 수도 있다.
https://t1.daumcdn.net/cfile/tistory/27118142535CCF060A
메모리를 사용한 매개변수를 전달
두번째나 세번째 방법의 경우 전달되는 매개변수의 개수나 길이에 제한이 없기 때문에 몇몇 운영체제에서 선호하는 방식이다.
System Call Interface(시스템 콜 인터페이스)가 하는 중요한 기능 중 하나는 사용자 레벨 요청(어플리케이션)에 대해 blokcing I/O와 nonblocking I/O 중 무엇을 선택하느냐와 관련되어있음.
어플리케이션이 blocking 시스템 콜을 호출하는 경우에는 해당 시스템 콜을 호출한 쓰레드의 실행이 중단된다. 일반적으로 I/O 장치에 의해 수행되는 물리적인 행위들은 일반적으로 비동기적(I/O 장치마다 물리적 행위들을 수행하는데 걸리는 시간이 다양하고 예측할 수 없기 때문에)으로 작동한다.
recvfrom 함수는 recv함수와 동일하게 데이터를 수신받기 위해서 사용되는 함수이다. ( sendto 와 send ) recvfrom함수는 비연결지향성으로 SOCK_DGRAM으로 생성된 소켓 연결에서 데이터를 수신한다.
- I/O 작업을 처리하기 위해 User Level에 있던 Application이 시스템 함수를 호출한다 (→ system call).
- 이 때 context-switching 이 발생
- Kernel Level에서 해당 I/O 작업 진행, I/O가 끝날 때까지 유저 프로세스 대기
- 끝나기 전에는 함수가 반환되지 않기 때문에 커널이 작업을 완료하기전까지 유저 프로세스는 작업을 중단한 채 대기
- I/O 작업이 CPU 자원을 거의 쓰지 않기 때문에 Blocking 방법은 CPU 자원 낭비가 심함
- 애플리케이션 관점에서 보면 아무런 동작도 안하는 것처럼 보이지만 실제로는 커널에서 I/O 작업을 수행하느라 block되어 있음
- 바로 이 부분이 blocking I/O의 문제점이며 개선 포인트가 됨
- 이러한 blocking 방식의 비효율성을 극복하고자 만들어 진 것이 non-blocking 방식이다.
- 작업 완료 후 데이터를 반환하게 되면 그 때가 되어서야 Application단의 스레드에 걸렸던 block이 풀림
Non-Blocking I/O Model
non-blocking 방식은 I/O 작업을 진행하는 동안 유저 프로세스의 작업을 중단시키지 않음
- 유저 프로세스가 I/O를 처리하기 위해 커널에 함수를 호출하면(→ system call )
- 커널에서 함수의 진행 상황과 상관없이 바로 결과를 반환
- 이 때 반환되는 결과는 반환하는 순간에 가져올 수 있는 데이터에 해당
- 처음에는 가져올 수 있는 데이터가 없겠지만 시간이 지나면서 가져올 수 있는 데이터가 생겨나게 됨
- 서버는 클라이언트가 요청한 사이즈에 맞는 데이터를 반환하기 위해 데이터를 축적
- 클라이언트가 따로 반환되는 값이 원하는 사이즈가 되었는지 계속해서 확인(→ polling )
- Non blocking Model은 결국 반환되는 데이터가 준비가 되었는지(원하는 값이 되었는지) 확인하는 과정에서 수많은 클라이언트의 요청이 동시 다발적으로 일어날 경우, CPU에게 적지 않은 부담이 될 수 있는 I/O Model임
- 데이터의 축적이 끝났을 때, 반환되어 클라이언트에서 요청한 사이즈의 데이터를 받아올 수 있게 됨
Asynchronous I/O Model
Event-driven Model로도 불리는 이 모델은 Non-Blocking에서 제기된 문제를 해결하기 위해 고안되었음. Non-Blocking I/O Model에서 처럼 애플리케이션에서 데이터 준비가 되었는지 계속해서 확인하는 것이 아니라,
- 작업 요청
- 유저 프로세스는 다른 작업 수행
- kernel Level에서 데이터가 준비되면 콜백 또는 이벤트를 발생시켜 애플리케이션에 알림(→ notify )
- 그 때 그에 따른 작업 처리
운영체제 단계의 비동기 API를 통해 이루어지며 I/O작업이 completion이 되면 그에 적합한 Handler를 이용해 처리
Synchronous
작업을 요청한 후 해당 작업의 결과가 나올 때까지 기다린 후 처리하는 것으로 I/O 작업에 대한 readiness를 기다린다. 특정 I/O 작업을 하기 위한 준비가 되었는지에 집중하는 것이다. I/O 작업 준비에 대한 이벤트의 발생을 기다렸다가 해당 이벤트가 발생하면 그에 따른 적합한 처리를 한다.
출처:https://sharplee7.tistory.com/96