본문 바로가기
프로그래밍/기타

[시스템] Control Flow와 Exceptions

by 카프카뮈 2021. 5. 2.

최근 대학에서 시스템 프로그래밍을 공부하고 있는데, 

여기에서 예외 처리에 대한 내용이 언급되었다.

 

Java를 쓰는 만큼 예외 발생이나 핸들링에는 익숙하지만,

생각해보면 C를 쓸 때에는 예외 개념이 없었으니까...당시엔 어떻게 예외를 처리했나 궁금하던 터였다.

 

그래서, 오늘 배운 내용을 간단히 정리해보려고 한다.

다룰 내용은 다음과 같다.

  • 프로세스와 Control Flow
  • Control Flow를 변형하는 특수한 사례들
  • Exceptions

1. 프로세스와 Control Flow

우리가 사용하는 프로그램들은, 명령어(instruction)들의 집합이다.

그리고 이러한 프로그램이 메모리에 적재되어 실행되는 중일때, 그것을 프로세스라고 한다.

즉 프로세스는, "an instance of a running program" 인 것이다.

 

프로그램이 메모리에 올라가 프로세스가 되면, CPU는 해당 프로세스에 들어있는 명령어를 순차적으로 실행한다.

아래와 같은 일련의 명령어 실행 흐름을 Control Flow라고 한다.

명령어를 순차적으로 실행하는 CPU

그런데 이러한 Control Flow에 따르지 않고, CPU가 임의로 순서를 바꾸어 명령어를 실행해야 하는 경우가 있다.

jump(C언어의 goto, 여기서는 nonlocal jump를 제하고 설명)를 사용해서 코드 중간으로 건너뛰는 것을 요청하는 경우나, branch(조건문을 통한 분기)를 통해 원하는 분기의 코드를 실행하는 경우가 그 예가 된다. 또한 서브루틴의 call/return, 즉 함수의 호출과 반환 역시 마찬가지가 된다.

 

다만 이는 프로세스의 상태가 바뀌었기에 Control Flow가 흐트러진 것이며, Control Flow 역시 해당 프로세스를 벗어나지 않는다는 점을 유의해야 한다. 즉, 내가 함수를 호출하거나 goto문을 써도 프로세스(프로그램) 바깥의 무언가로 Control이 이동하지는 않는다는 이야기!

 


2. Control Flow를 변형하는 특수한 사례들

그렇다면 프로세스 바깥에서의 상태 변화를 이유로 Control Flow가 바뀌는 경우가 있을까?

혹은, 프로세스의 요청에 인한 것이라도 프로세스 바깥으로 Control Flow가 이동하는 경우가 있을까?

그러한 경우, 프로그램의 흐름은 어떤 형태가 될까? 지금부터 예시를 보면서 이해해 보자.

 

만약 프로세스가 컴퓨터의 디스크에서 데이터를 가져와 달라고 요청하면 어떨까?

C언어에서는 이를 fopen, fread, fscanf 등의 여러 함수를 통해 구현할 수 있도록 준비해 두었다.

그러나 우리가 실제로 이 명령어를 사용하게 되면, 프로세스가 직접 디스크에 접근하여 파일을 가져오는 것은 아니다.

하드웨어에 직접 접근할 경우 해당 하드웨어가 어떤 설계를 따르냐에 따라 복잡한 문제를 야기할 수 있기 때문에, OS는 커널이라는 핵심 프로그램에 해당 하드웨어에 대한 추상화된 인터페이스를 넣어두고 있다.

즉 커널을 통해 디스크를 읽는 명령을 요청하면, 우리는 하드웨어에 대해 알 필요도 없고, 또한 자잘한 예외나 여러 기기의 중복 접근으로 인한 충돌 등까지 막을 수 있는 부수적 이득을 얻을 수 있는 것이다.

그러나 이는 다른 문제를 가져온다. 그러면 우리가 fopen 명령어를 실행하는 순간, CPU는 해당 프로세스와 커널 중 어느 것을 실행하고 있을까?

힌트가 될 이미지. 파일 입출력 시 user space에서 kernel space로 이동하는 과정이다.

* 상단의 이미지 및 커널에 대한 일부 설명은 링크를 참조했다.

 

Kernel System Calls

Reprinted with permission of Linux Magazine Kernel System Calls by Alessandro Rubini This article is the first step towards an understanding of how kHTTPd can take the role of a web server while never leaving kernel space. System Calls: the Facts One of th

www.linux.it


다른 경우를 보자. 만약 프로세스가 네트워크로 특정한 요청을 보냈고, 그에 대한 응답을 받아야 한다고 하자.

만약 상대방 서버에서 내 컴퓨터로 데이터를 보냈다면, 프로세스는 그것을 어떻게 알 수 있을까?

데이터가 도착한 것을 알 방법은 두 가지이다. 하나는 데이터가 올때까지 계속 대기하는 것, 또 하나는 데이터가 왔다는 신호를 받는 것이다.

 

이에 대한 좋은 예시를 인용해 보겠다.

당신이 사무실에서 일을 하고 있는데, 오늘 12시에서 5시 사이에 상담을 원하는 손님이 오기로 했다고 하자.

이때, 당신은 해당 손님이 언제 올 지 모르며, 기다리는 동안 다른 업무도 처리해야 한다.

그런데 손님이 오는 것을 확인한다고 계속 문 앞에 서서 바깥을 보고 있으면 어떨까? 다른 업무를 수행하는 것이 불가능할 것이다.

그러한 이유로, 합리적인 사람이라면 문을 닫아놓고 노크나 초인종이 울리길 기다리며 업무를 볼 것이다.

업무를 보던 도중 노크 소리가 나면, 하던 업무를 잠시 미뤄두고 상담을 하고, 상담이 끝나면 다시 업무를 이어서 하는 것이다.

 

위의 예시를 통해, 우리는 네트워크로 요청한 데이터를 기다리는 경우, 이에 대한 신호가 왔을 때 관련된 업무를 수행되면 된다는 것을 알게 되었다.

그렇다면, 프로세스 실행 도중 네트워크로 값이 전송되어 신호가 온 직후, CPU는 해당 프로세스와 커널 중 어느 것을 실행하고 있을까?


이외에도 우리는 프로세스가 중단되거나 잠시 교체될 만한 여러 상황을 알고 있다.

  • 연산 도중 숫자를 0으로 나누면 어떻게 처리할 것인가? 
  • 유저가 프로세스 실행 도중 CTRL+C(리눅스에서 프로그램 종료 명령어)를 누르면, 어떻게 처리할 것인가?

3. Exceptions

위와 같은 Control Flow의 프로세스 변경 문제 때문에, Control Flow에는 예외적인 몇 가지 상황이 정의되어 있다.

하이 레벨 메카니즘에서는 다음과 같은 경우들이 정의되어 있다.

  • Process Context Switching : OS가 timer를 통해 프로세스를 스위칭하는 경우
  • Signals : OS에 의해 특정한 시그널을 받고 프로세스를 종료하는 경우
  • Nonlocal jumps : C언어 등에 implemented된 기능으로, 프로세스 바깥으로 이동할 경우

그리고 로우 레벨 메카니즘에는, 이제 우리가 다루려고 하는 Exceptions가 정의되어 있다.


Exceptions의 정의는 다음과 같다: "Change in control flow in response to a system event"

그리고 조금 더 길게 말하면, 다음과 같다: "An exception is a transfer of control to the OS kernel in
response to some event".

즉 Exception은 특정한 이벤트가 발생할 경우, control을 OS Kernel로 변경/전송해주는 역할을 한다는 것이다.

Exceptions의 종류

Exceptions에는 크게 4가지의 분류가 존재한다.

이에 대해서는 다음 포스팅에서 다뤄보려고 한다.

 

잘못된 내용이 있다면 지적 부탁드립니다. 감사합니다.

반응형

댓글