예외처리 #2 [CSAPP Chap 8]

앞서 논한 예외는 운영체제가 하드웨어를 제어하는 저수준 메커니즘이었다. 이제부터는 이 메커니즘을 활용해서 운영체제가 수행하는 일들을 확인 해 볼 수 있다.

 


2025.10.20 - [컴퓨터 이론/CS:APP] - 예외처리 #1 [CSAPP Chap 8]

 

예외처리 #1 [CSAPP Chap 8]

예외, 프로세스, 시그널 순으로 알아본다.예외예외는 CPU가 정상적인 프로그램 실행 흐름을 벗어나 미리 정해진 운영체제 코드를 실행하도록 만드는 사건이다. 프로세서 상태에 어떤 변화가 생

hyeonistic.tistory.com

 

 

프로세스와 동시성

CPU 코어는 하나이지만 동시에 프로그램을 켜놓을 수 있는 것은 사이사이에 문맥 교환을 아주 빠르게 반복하기 때문이다.

문맥 교환은 기존 내용을 저장하고, 나중에 그대로 복원하는 것이 핵심이다. 컴공에서는 이 기존 내용을 문맥이라고 부른다.

다음과 같은 정보가 문맥에 포함된다 :

  • 프로그램 카운터 : “어디까지 했는지”를 명시함
  • CPU 레지스터 : 계산하던 중간값의 내용은 뭐였는지를 명시함
  • 메모리 정보 : 어떤 메모리 영역을 사용하고 있었는지를 명시함

문맥 교환을 시작 할때, 시작까지 하고 있던 프로세스를 멈추면서 이와 같은 내용들을 저장해둔다. 그리고 전환된 내용을 수행하다가 돌아올 때가 되면 기존의 내용을 복원해서 하던 일을 마저 수행하게 된다.

운영체제는 문맥 교환 타이밍을 하드웨어 타이머로 인한 인터럽트를 통해 측정한다. 프로그램의 의지와 상관없이 타이머 칩이라는 외부 하드웨어 장치로부터 오는 비동기적인 신호이기 때문에 인터럽트가 맞다.

운영체제는 이 타이머 인터럽트를 이용해서 한 프로세스가 CPU를 너무 오래 사용하는 것을 막고, 여러 프로세스에게 CPU 사용 시간을 공평하게 나누어준다. 이 덕분에 우리는 여러 프로그램을 동시에 사용하는 듯한 경험을 할 수 있다.

 

 

프로세스의 메모리 구조

앞서 우리는 문맥 교환을 통해 여러 프로세스를 번갈아 실행하는 원리를 배웠다. 하지만 이는 각 프로세스가 서로의 메모리를 침범하지 않는다는 안전이 보장될 때만 의미가 있다.

운영체제는 이 문제를 가상 메모리라는 방법으로 해결한다. 운영체제는 각 프로세스에게 가상 주소 공간에 대한 단독 배정이라고 전제시키고, 실제 메모리 상에서 분리된 형태로 작동하게 끔 한다.

아파트 위와 아랫층이 동일한 레이아웃일 지언정 내용 자체는 구분되어있다고 생각하면 직관적이다.

이 가상 주소를 물리 주소로 변환해주는 역할은 CPU 안에 있는 메모리 관리 장치가 운영체제의 도움을 받아 실시간으로 처리한다. 프로세스 A의 “Something”과 프로세스 B의 “Something”은 이름은 같을 지언정 서로 다른 메모리 주소로 안내를 하게 되고 이로써 서로 침범할 일이 원천적으로 차단되는 것이다.

이런 구조는 프로그램 개발에 있어 메모리의 제약 사항을 보다 적게 고민하게 만들어준다.

 

 

프로세스 제어

운영체제가 어떻게 새로운 프로세스를 만들고 관리하는지 알아본다.

fork() : 분기하다는 뜻 그대로, 현재 실행 중인 프로세스를 거의 완벽하기 복제해서 새로운 ‘자식 프로세스’를 만든다. 이 과정은 마치 세포 분열과 같다 :

  1. 부모 프로세스가 fork() 를 호출한다.
  2. 운영체제는 부모의 메모리, 레지스터 등 모든 문맥을 그대로 복사해서 자식 프로세스를 만든다.
  3. 이제 부모와 자식, 두 개의 프로세스가 fork() 가 호출된 바로 그 지점부터 똑같이 실행을 이어간다.

중요한 것은 같은 코드래도, fork() 에 대한 반환값이 다르다.

  • 부모에게는 새로 만들어진 자식의 PID가 반환된다.
  • 자식에게는 0이 반환된다.

프로그램은 이 반환값의 차이를 통해 자신이 부모인지 자식인지 구별해서 서로 다른 작업을 수행 할 수 있다.

fork() 를 통해 만들어진 자식 프로세스는 exec() 내지 execve() 를 통해 프로세스 내부의 내용을 전부 전환 할 수 있다. 중요한건 프로세스 ID는 바뀌지 않는다는 점이다. 이로써 쉘이 프로그램을 실행하는 과정을 확실히 할 수 있다.

  1. fork() 호출 : 쉘은 자기 자신을 복제하여 자식 프로세스를 만든다.
  2. execve() 호출 : 자식 프로세스는 execve("ls", ...) 를 호출하여 자기 자신을 ls 프로그램으로 전환한다.
  3. wait() 호출 : 쉘은 wait() 을 호출해서 자식 프로세스 ls 가 끝날 때까지 잠시 기다린다.
  4. 종료 및 복귀 : ls 프로그램 실행이 끝나면 기다리던 쉘이 다시 깨어나 다음 명령어 입력을 받는다.

fork-and-exec 패턴은 유닉스 시스템에서 프로그램을 실행하는 가장 근본적인 방식이다.

 

 

'컴퓨터 이론 > CS:APP' 카테고리의 다른 글

게임과 앱 개발에 중요한 [CSAPP Chap 9]  (0) 2025.10.23
예외처리 #3 [CSAPP Chap 8]  (0) 2025.10.20
예외처리 #1 [CSAPP Chap 8]  (0) 2025.10.20
링커 #2 [CSAPP Chap 7]  (0) 2025.10.20
링커 다루기 [CSAPP Chap 7]  (0) 2025.10.20