gRPC를 공부하던 도중 우연히 README 문서에서 이 논문을 첨부한 것을 보고 나도 한번 읽어봤다.
보통 논문을 첨부한 경우, 읽어보기는 하지만 크게 신경 쓰지 않고 넘어갔는데 gRPC를 공부하면서 강의 슬라이드도 만드는 편이었고
또 OS 공부라면 늘 신기하면서 재밌었기 때문에 며칠에 걸쳐 읽으면서 번역도 하고 정리를 했다.
예상 외로 논문이 발표 된 지 얼마 안되었고(2019. 5), 또 fork는 OS API 중 대부분의 앱에서 사용되는 API이기 때문에 읽을 가치가 있다고 생각했다.
생각보다 중요한 논문임에도 불구하고, 한국어로 작성된 블로그 글이 없어 의외로 놀랐다.
요약
fork() 함수의 개념은 컴퓨터가 발명 된 초기에 시분할 시스템이 사용될 무렵부터 정립되어 있었다.
현대 컴퓨터에서 사용되고 있는 fork() 형태는 PDP-7 컴퓨터에서 사용하기 위한, 어셈블리어로 작성된, Unix에서 구현되었다.
이 때 Unix를 구축한 켄 톰프슨(Thompson)과 데니스 리치(Ritchie)는 fork()를 구현할 때 프로그램이 사용하고 있는 메모리를 통째로 복사하는 형태로 구현했다.
당시 프로세스를 복제하는 방법으로는 메모리를 공유하는 방법과 톰프슨과 리치가 구현한 방식처럼 메모리를 통째로 복사하는 방법 모두 고안이 된 상태였다.
당시의 컴퓨터의 구조와 프로그램의 복잡도가 현대의 컴퓨터에 비해서 상당히 낮았기 때문에 최초로 구현한 fork()의 형태가 계속해서 사용되었다.
그러나 프로세서의 동작 속도와 메모리 접근 속도의 차이, 더욱 더 복잡해진 현대 컴퓨터에게 있어서 메모리를 통째로 복사하는 것은 고통이었다.
스레딩(Threading)과 멀티프로세싱(multiprocessing) 같이 동시성 컴퓨팅이 보편화되면서 메모리를 통째로 복사한다는 fork()의 동작 방식은 메모리의 동기화에 방해가 되었다는 것이다.
예를 들어 Lock을 가지고 있는 동작이 실행되던 도중 fork()가 발생하면 deadlock이 발생할 수 있다는 것이다.
그래서 이전의 프로그램들은 fork() 함수를 고려할 필요 없이 프로그램을 작성했지만, 현대의 프로그램들은 fork()의 동작 방식 때문에 fork()가 사용되는 것을 고려해서 작성하거나, 미리 fork()를 하는 pre-fork() 방식으로 짜게 된다는 것이다.
현대적인 방법으로는 spawn을 사용하는 것을 권장한다는 내용이다.
fork()는 exec()과 조합을 통해서 주로 사용되는 OS API다,
OS를 소개하는 대부분의 책에는 fork+exec 방식의 긍정적인 면만 소개해서 아쉽다고 논문 저자가 쓰기도 했다.
내가 아직 fork, exec API를 직접 사용하는 경험은 없었지만, 언젠가는 마주하게 될 확률이 높아 보이니, 썩 나쁘지 않은 시간 투자 대비 지식이었다.