입출력(I/O)이란 컴퓨터 시스템이 컴퓨터 외부의 주변 장치들과 데이터를 주고받는 것을 말합니다.
입출력 방식에는 동기식 입출려과 비동기식 입출력이 있습니다.
프로그램이 디스크에서 어떠한 정보를 읽어오라는 요청을 했을 때, 디스크 입출력이 완료되기까지는 어느 정도의 시간이 걸리게 됩니다.
이 때, 동기식 입출력은 입출력이 진행되는 동안 그 프로그램의 다음 명령을 수행하지 않고 기다리게 됩니다.
그러다가 입출력이 완료되어 인터럽트를 통해 그 사실이 전달된 후에야 CPU의 제어권이 그 프로그램에게 넘어가서 다음 명령을 수행할 수 있게 됩니다.
따라서, 동기식 입출력에서는 입출력 연산이 끝날 때까지 CPU는 아무 일을 할 수 없게 됩니다.
이 경우는 논 블록 동기 입출력입니다.
CPU의 명령 수행 속도는 빠른 반면 외부 장치에서 데이터를 읽어오는 등의 입출력 연산은 상대적으로 속도가 느립니다. 그럼에도 불구하고 입출력이 완료될 때까지 기다렸다가 사용자 프로그램에게 CPU 제어권을 방식은 CPU가 입출력이 완료될 때까지 아무 일도 하지 못하기 때문에 자원의 낭비가 발생합니다.
따라서 일반적으로 프로그램이 입출력을 수행중인 경우 CPU를 다른 프로그램에게 이양해 CPU가 계속 쉬지 않고 일할 수 있도록 관리합니다.
입출력이 완료될 때까지 그 프로그램에 CPU를 할당하더라도 명령을 수행하지 못하는 상태를 만들어야 합니다.
위와 같은 상태를 봉쇄 상태(block state)라고 합니다.
봉쇄 상태의 프로그램에게는 CPU를 할당하지 않고, CPU를 할당하면 곧바로 작업을 수행할 수 있는 프로그램들에게만 CPU를 할당합니다.
예시
A라는 프로그램이 디스크에 원래 1이던 파일의 내용을 3으로 바꾸는 입출력 연산을 요청했습니다.
입출력 연산을 수행중일 때 A에게서 CPU를 선점해 B에게 할당했습니다.
프로그램 B가 CPU를 할당받고 수행중일 때, 이 프로그램 역시 입출력 요청을 할 수 있습니다. 프로그램 B가 요청한 입출력 연산이 A가 접근하려는 곳과 동일한 파일의 내용을 1 증가시키는 연산입니다.
A => 1->3
B => 1 증가
이 경우 매 시점 두 개 이상의 입출력 연산을 수행할 수 있다면, 컨트롤러는 A와 B의 순서를 바꾸어 수행할 가능성이 있습니다.
즉, 1 -> 3 -> 4로 바뀌어야 하는데, 1 -> 2 -> 3으로 바뀔 수도 있다는 것입니다.
따라서 동기식 입출력에서는 입출력 요청의 동기화를 위해 장치별로 큐(queue)를 두어 요청한 순서대로 처리할 수 있도록 했습니다.
프로그램 A가 먼저 요청했으면 이를 먼저 큐에 넣고, 그 후에 발생한 B의 요청을 A의 요청 뒤에 삽입합니다.
동기식 입출력은 입출력이 완료될 때까지 입출력과 관련 없는 프로그램을 수행하도록 하고, 요청된 입출력 연산이 완료되면 CPU에게 입출력이 완료되었음을 알려주는 방식으로 진행합니다.
연산 완료의 통보는 인터럽트를 통해서 수행되며, 이 경우 운영 체제 커널은 인터럽트 처리 루틴으로 가서 입출력 연산을 끝낸 프로그램이 CPU를 할당받을 수 있도록 그 프로그램의 상태를 봉쇄 상태(block state)로부터 해제시키게 됩니다.
비동기식 입출력은 입출력 연산을 요청한 후에 연산이 끝나기를 기다리는 것이 아니라 CPU의 제어권을 입출력 연산을 호출한 그 프로그램에게 곧바로 다시 부여하는 방식을 말합니다.
비동기식 입출력에서는 입출력이 필요없는 작업을 먼저 수행하고, 읽어오는 데이터가 반드시 있어야 수행할 수 있는 일들은 입출력이 완료된 후에야 수행하게 됩니다.
또한, 입출력 요청이 디스크에서 읽어오는 요청이 아니라 디스크에 쓰는 요청이라면 쓰기 작업이 완료되기 전에도 다음 명령을 수행할 수 있으므로 비동기식 입출력이 사용될 수 있습니다.
일반적으로는 입출력 요청을 운영 체제에게 하게 되면 해당 프로그램의 입출력이 완료될 때까지 그 프로그램을 봉쇄시키는 동기식 입출력을 사용합니다.
이 때 운영 체제는 장치별로 입출력 처리를 기다리는 프로세스를 줄 세워 관리함으로써 동기성을 보장하게 됩니다.
마지막으로 비동기/동기, 블록/논블록에 대해서 잘 정리한 포스트를 소개합니다.
https://musma.github.io/2019/04/17/blocking-and-synchronous.html
https://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/
https://deveric.tistory.com/99