동기, 비동기, 블락, 논블락의 개념정리
1. sync, async
동기와 비동기의 개념이다.
동기란, 서브루틴의 종료 순서가 보장되는 것이다. (서브루틴을 메인루틴이 책임)
메인 루틴이 서브루틴의 종료를 책임지며, 서브루틴의 종료가 메인 루틴의 관제 하에 이루어 지는 것이다.
메인루틴은 서브루틴이 종료되었는지 확인하거나(non-blocking), 서브루틴이 종료될때까지 멈추게 된다(blocking).
이로인해 메인 루틴은 서브루틴의 종료와 함께 서브루틴의 결과를 받게된다.
비동기란, 서브루틴의 종료 순서가 보장되지 않는 것이다. (서브루틴을 서브루틴이 책임)
메인 루틴이 서브루틴의 종료를 책임지지 않으며, 대게 서브루틴의 종료는 콜백 또는 시그널을 통해 메인 루틴에 전달된다.
메인 루틴은 서브루틴의 실행과 함께 종료시 알려줄 콜백을 같이 넘겨주게 된다.
이후 서브루틴이 종료될경우 같이 넘어온 콜백을 통해 메인루틴에 알려주게 되며 메인루틴은 콜백을 통해 서브루틴의 종료를 알게된다.
2. blocking, non-blocking
블록과 논블록은 메인 루틴이 서브루틴의 실행시간동안 정지가 되냐 마냐의 문제다.
블록킹이란, 메인루틴에서 서브루틴을 실행시키는 동안 메인루틴이 종료되는것을 의미한다.
서브루틴이 진행되는 동안 메인루틴은 서브루틴이 종료될때까지 아무것도 하지 못한다.
논블록킹이란, 경우 메인루틴이 서브루틴이 실행되는 동안 종료되지 않는것을 의미한다.
논블로킹의 경우 서브루틴이 실행되는 동안 메인루틴에서도 작업이 이루어질 수 있다.
3. sync, async / block, non-block
동기와 비동기, 블록과 논블록은 각 개념으로 본다면 크게 어렵지 않다.
하지만 이 두개의 개념이 섞이게 된다면 그때부터 혼란이 오기 시작한다.
3.1 sync, block
우선 동기와, 블록킹의 관계부터 본다.
동기는 실행의 결과를 메인 루틴이 책임지는것,
블록킹은 서브루틴이 실행되는 동안 메인루틴을 막는(blocking)것이다.
이에대한 예시로는 커널 I/O 작업이 있다.
블록킹 소켓의 시스템콜 recvfrom() 의 경우 소켓으로부터 데이터가 있을때까지 기다린 후, 해당 데이터를 커널 스페이스 -> 유저스페이스로 이동시킨다.

해당 예시를 보면 유저 스페이스에서 커널 스페이스 시스템콜을 호출한 후 해당 데이터가 올동안 기다리다 데이터를 받은 후 유저 스페이스로 결과를 리턴해주는 모습을 보인다.
3.2 sync, non-block
동기와 논블록의 관계다.
동기로 동작하므로, 서브루틴의 결과에 대한 책임을 메인루틴이 지고 있으며, 메인 루틴은 서브루틴이 끝나기를 기다림과 동시에, 자신의 작업을 진행한다.
또한 서브루틴의 종료를 확인하기 위해 주기적으로 확인을 한다.
논블록킹 소켓의 시스템콜 recvfrom() 의 경우 받을 데이터가 없으면 EWOULDBLOCK 또는 EAGAIN 라는 값을 즉시 전달해주게 되고, 값이 있다면 해당 값을 유저 스페이스로 전달해준다. (단 데이터가 있나없나를 확인할때는 논블럭이지만, 데이터를 실질적으로 복사하는 기간에는 블록된다)

해당 예시를 보면 유저스페이스에서 커널 스페이스로 recvfrom() 콜을 계속 날리고, 커널에서 데이터가 없는경우 기다리지 않고 EWOULDBLOCK을 즉시 리턴해준다.
유저 어플리케이션은 해당 데이터를 확인하기 위해 계속해서 recvfrom()을 날리게 되고 값이 준비가 되면 그때 값을 직접 받아온다.
3.3 async, block
비동기와, 블록의 관계다.
개념적으로 말하자면, 서브루틴을 실행 후 그에대한 책임은 없지만 해당 서브루틴이 끝나기를 기다리는 것이다.
IBM에서는 select()를 통한 I/O 멀티플렉싱을 이 모델로 말하지만, 맞다 아니다에 대한 의견이 나오고 있다.
나는 아니다 쪽에 가깝지만 일단 그렇다고 소개된 모델이니 언급하고 넘어간다.
우선 select란 특정 fd(소켓)들을 관찰하다 데이터가 준비된 fd가 있으면 해당 fd를 리턴해준다.
(sync, blocking 시스템콜 timeout이 없다면)
select(2) - Linux manual page
select(2) — Linux manual page SELECT(2) Linux Programmer's Manual SELECT(2) NAME top select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O multiplexing SYNOPSIS top #include int select(int nfds, fd_set *restrict rea
man7.org
이후 특정 fd에서 데이터가 준비되면 논블록킹 I/O를 통해 fd의 데이터를 읽어오는 방식이다.
즉 sync, blocking 시스템콜인 select를 통해 여러개의 fd들을 관측하다, 특정 fd에서 데이터가 준비되면
non-blocking 시스템콜을 통해 해당 데이터를 읽어오는 방식이다.

실제로 블록이 되는 요소가 select라는 동기 시스템콜이기 때문에 이 모델이 async, block의 예제로 적절하지 않다는 의견들이 있긴 하지만, 여기선 그렇다 정도로만 언급하고 넘어간다.
3.4 async, non-block
비동기와 논블록에 대한 관계다.
비동기 작업, 즉 메인루틴이 해당 작업의 결과를 책임지지 않으며, 해당 비동기 작업이 끝나든 말든 자신의 일을 한다.
단 해당 서브루틴이 끝나게 되면 콜백 또는 시그널을 통해 메인루틴에 알려지게 되며 메인루틴은 그때 서브루틴에 대한 작업을 수행하게 된다.
aio_read() 시스템콜을 통해 커널에 데이터를 요청하면, 커널은 데이터의 유무와 상관없이 즉시 결과를 주게 된다.
이후 실제 데이터가 준비되고, 데이터가 들어오게 되면 시그널을 통해 유저스페이스로 알려지게 된다.

예제를 보면 aio_read()의 호출과 동시에 리턴이 이루어진다. 이후 어플리케이션은 자신의 작업을 계속 진행하게 되고 커널로부터 해당 작업이 완료된 시점에서 시그널을 통해 어플리케이션으로 알려지게 된다.
4. 결론
4.1 동기
메인루틴이 서브루틴에 대한 종료를 책임짐.
서브루틴의 리턴이 서브루틴의 종료와 같은 시점에 이루어짐
4.2 비동기
메인 루틴이 서브루틴에 대한 종료를 책임지지 않음
서브루틴의 리턴이 서브루틴의 종료와 같은 시점에 이루어지지 않음.
서브루틴이 종료되면 콜백, 시그널등을 통해 알려줌.
4.3 블록
서브루틴이 실행되는 동안 메인루틴이 멈춤.
4.4 논블록
서브루틴이 실행되는 동안 메인루틴이 멈추지 않음.
4.5 동기 / 블록
메인루틴이 서브루틴이 끝날때까지 대기하다, 서브루틴이 종료되면 결과값과 함께 리턴해주고, 그때서야 메인 루틴이 진행됨.
4.6 동기 / 논블록
메인루틴은 서브루틴이 진행되는 동안에도 자신의 일을 계속 진행함.
메인루틴은 서브루틴이 끝났는지에 대한 확인을 주기적으로 진행
서브루틴이 끝나게 되면 메인루틴은 해당 서브루틴의 결과를 직접 가져옴.
4.7 비동기 / 블록
메인루틴은 서브루틴의 종료에 대한 책임을 지지 않지만, 서브루틴이 끝날때까지 대기함
4.8 비동기 / 논블록
메인루틴은 서브루틴을 실행시키고 자신의 일을 계속 진행함.
서브루틴은 자신의 일이 끝나면 시그널 / 콜백 등을 통해 메인루틴에게 알려줌