본문 바로가기

면접질문[CS]/알고리즘 & OS

동기 비동기 블로킹과 논블로킹 2x2 매트릭스 [ 운영체제(OS) 면접질문8 ]

 

WHY

운영체제에서 헷갈리는 질문 중 Top 5 중 하나가 아닐까 한다.

 

함수의 호출과 관련해서 프로세스의 자원(CPU)의 제어 관점과

 

함수의 "결과"의 관점으로 프로세스를 운영하는 정책과 관련된 질문이다.

 

자원 사용의 측면(블로킹, 논블로킹)과 함수 결과 관점(동기 비동기)으로 4가지의 매트릭스가 생성될 수 있다.

 

이번 내용을 정리하기 전에 비동기가 Non-blocking 아닌가?라고 생각했다.

 

해당 질문이 들어왔으면 고대로 면접관의 체크리스트에서 -점수가 기록되었을 답변으로 이어졌을 것 같다.

 

Blocking을 프로세스의 "대기"상태와 관련지어서 이해하자.

 

컴퓨터 아키텍처를 살펴보면 CPU의 시간과 IO의 시간이 서로 다르게 흘러간다는 것을 알 수 있다.

 

CPU의 시간은 IO시간보다 더 빠르고 바쁘게 움직이며 모든 면에서 더 빠르다. 그리고 해야 할 일도 산더미다.

 

CPU가 IO를 위해 기다린다는 것은 IO가 CPU를 기다리는 것과 상당히 다르다. 둘의 시간 환경이 완전히 다르기 때문.

 

그렇기에 CPU가 IO작업을 처리하는 시간을 그대로 "대기"하는 것은 운영체제 입장에서는 유쾌하지 않다.

 

비싼 자원의 사용 시간을 저렴한 자원의 사용 시간동안 기다린다?

 

이런 정책을 고집하면 OS 설계 리더가 꿀밤을 한대 때릴지도 모르겠다.

 

블로킹 처리. 사용자는 시스템 콜을 호출하고 커널의 응답까지 사용자 프로세스(작업)가 막혀(block) 버린다! 
사용자 프로세스는 커널을 호출하지만 자신의 작업을 계속 진행한다. 그러면 결과는? 결과 처리는 sync, async에서 자세히 얘기를 나누도록 한다. [해당 그림에서는 계속 결과를 확인하는 과정을 가진다(sync)]

 

블로킹과 논블로킹의 핵심은 호출한 쪽이 제어권을 가지는가의 유무이다.

 

호출한 쪽을 A라고 하고 호출된 쪽을 B라고 가정하자. [ 보통은 A가 애플리케이션 쪽 B가 커널 쪽 ]

 

[ 커널 스레드 작업의 경우 강제적으로 뺏을 수가 없는 작업이 대부분이다. ]

 

A가 B에게 제어권을 넘기고 기다리게 되면 이는 blocking이다.

 

A가 B에게 제어권을 잠깐 넘기고 바로 돌려받으면 이는 non-blocking이다.

 

좀 더 자세한 문장으로 풀어보면.

 

CPU야 쉬지마!

Blocking

- A에서 호출한 함수로(B)로 제어권을 넘긴다.

A는 B의 작업이 끝나면 리턴값과 함께 제어권을 다시 돌려받는다.

A의 작업은 B작업이 진행되는 동안 멈추게 된다. [ 비효율적! ]

 

그래 CPU는 계속 움직여야해

Non-Blocking

- A에서 B로 제어권을 넘기긴 하지만, 바로 제어권을 돌려받고 A의 작업을 계속 수행한다.

A는 B의 결과를 기다리는게 아니라 자신의 작업을 계속 수행하면 된다.

으잉? 그러면 B의 결과를 언제 받는지 어떻게 알지?

 

여기서 sync와 async 개념이 등장한다. 호출한 B의 결과의 관점인 것이다.

 

A는 어떻게 B의 결과를 언제 사용할 수 있는지 알게 될까? 

동기와 비동기. 동기는 시스템 콜을 호출하고 결과를 기다린다. 비동기는 콜백을 통해 결과를 받는다.

 

함수의 결과

 

특정 기능을 사용하거나 작업을 처리하기 위해서 우리는 응집된 로직을 소유한 함수를 사용하게 된다.

 

블로킹과 논블로킹은 자원(CPU)을 사용하는 프로세스의 제어권을 막히지 않고 계속 사용하는가

막힌 상태로 대기하는가의 여부였다.

 

여기서 논란이 되는 부분은 막히지 않고 사용하는 경우 결과를 어떻게 확인하는가였다.

 

어떤 응답이 올지 궁금할 때 우리는 3가지 방법으로 접근한다.

 

1. 눈앞에서 기다릴게.(blocking)

 

2. 작업이 완료되었는지 계속 물어볼거야.(polling)

 

3. 완료되면 말해줘.(callback)

 

가장 마음 편하고 수월한 방식은 "완료되면 말해줘" 방법이다. 자원이 넘치고 할 일이 없으면 눈앞에서 기다릴게 방법이 가장 쉬울지도 모르겠다.

 

그 어느 영역도 아니고 모호하면 계속 물어볼 거야 방식으로 자신의 작업을 진행하면서 다른 작업을 괴롭히면 된다.

 

Sync의 방식이 위의 1번과 2번이다.

 

작업이 완료될 때까지 기다려서 결괏값을 받고 자신의 작업을 수행하는 것

 

혹은 자신의 작업을 수행하는 동안 결괏값이 완료되었는지 계속 체크해보는 것이다.

 

Async의 방식은 3번째 방식이다.

 

B를 호출할 때 callback 함수를 같이 넘기고 B가 완료되면 callback 함수를 실행시켜 결괏값을 반환하게 하는 것이다.

 

이후 B의 결과를 활용해야 하는 작업을 수행하면 된다. 

 

블로킹 방식은 Sync와 잘 맞고

 

논블로킹 방식은 Async와 잘 어울린다.

 

블로킹과 논블로킹으로 동기와 비동기를 다시 살펴보자.

 

블로킹(Blocking)

 

제어권을 B로 넘기는 방식이다. 이 방식은 어차피 결과를 기다리게 되니 B에게 작업 완료 유무를 물어볼 필요가 없다. 

 

문제가 생겨 타임아웃이 된 게 아니라면 B의 리턴 값을 돌려받고 나서 자신의 작업을 계속 수행하면 된다.

 

여기에 굳이 콜백 함수를 추가해서 작업을 처리할 필요가 없다. [ 쓸데없는 짓에 가깝다. ]

 

블로킹의 경우 Sync 모델이 활용되며 Async 모델은 거의 사용하지 않는다.

 

논블로킹(Non-blocking)

 

A의 제어권은 그대로 유지되는 방식이다.  B의 결과를 어떻게 확인할 것인지에 대한 고민이 필요하다. 

 

Sync 방식으로 접근하면 Polling으로 접근해야 한다. B의 결과를 받아낼 수 있는지 주기적으로 물어보는 것이다.

 

늘 그렇듯 몇 번의 요청은 실패할 것이고 이를 효율적으로 조율해야 하는 스트레스를 안겨준다.

논블로킹은 Sync와 어울리지 않는다.

 

Async 방식으로 접근하면 callback을 B로 넘기고 A는 자신의 작업을 수행하다가 B의 작업이 끝나고 호출되는 callback을 통해 결과를 받아내면 된다.

 

논블로킹은 Async와 잘 어울린다.


마무리

 

직관적으로 이해하려고 접근하면 블로킹-동기 방식이 이해하기 쉽다.

 

하지만 현실 사회도 그렇고 생태계도 그렇듯 모든 사건과 진행이 인과적으로 혹은 순차적으로 진행되지 않는다.

 

자원의 효율성을 위해서 우리는 모든 작업이 "동시"에 실행되는 것처럼 느껴지기를 원한다.

 

현대의 OS는 병렬성(동시에 많은 작업을 처리하는)과 병행성(동시 실행처럼 느껴지는) 환경을 제공해주고 있다.

 

그래서 논블로킹, Async 개념을 직관적으로 이해하기가 어려운 게 아닌가 싶다.

 

뇌는 시간의 흐름에 따른 이해를 원하는데 논블로킹, Async는 그런 개념에 혼돈을 주기 때문...

 

동기와 비동기와 블로킹 논블로킹 개념은 프로그래밍 서비스에서도 사용되는 개념인데 OS와는 조금 다른 개념으로 사용되는 듯하다. [ 제어권, 결과 이런 것과는 별도로 요청 - 응답 효율성의 개념으로 사용된다. ]

 

그래서 더 헷갈리게 되는 질문..

 

기타 질문으로 프로세스와 관련된 질문을 끝내려고 했는데... 그게 쉽지 않다는 것을 알게 되었다.

 

잘못된 정보가 있으면 말씀해주시면 수정하도록 하겠습니다.


참고자료

블로그

  • 첼시팬님의 글 : link
  • codemcd님의 글 : link
  • fake-developer님의 글 : link
반응형