#8 운영체제 | 프로세스와 컨텍스트 스위칭

HYUN·2021년 2월 20일
0

OS | 운영체제

목록 보기
8/13
post-thumbnail

문맥 교환 (Context Switch)

문맥 교환(文脈交換, context switch)이란 하나의 프로세스가 CPU를 사용 중인 상태에서 다른 프로세스가 CPU를 사용하도록 하기 위해, 이전의 프로세스의 상태(문맥)를 보관하고 새로운 프로세스의 상태를 적재하는 작업을 말한다. 한 프로세스의 문맥은 그 프로세스의 프로세스 제어 블록에 기록되어 있다. 출처: 위키백과

A와 B 프로세스가 있다고 가정했을 때 CPU가 프로세스 A를 실행하다가 스케줄러에 의해 프로세스 B로 교체가 됩니다. 이렇게 변경되는 매커니즘을 이야기 하는데 이것을 이해하기 위해서 프로세스의 구조에 대해서 간단하게 알아보겠습니다.


프로세스(Process)의 구조*

프로세스의 구조를 살펴보기 위해서 프로그램이 어떻게 실행되는지 살펴보겠습니다.
하드웨어에 관한(CPU와 메모리의 관계 등) 어느정도 선행지식이 필요합니다.

우선 우리가 프로그램을 실행하면 해당 프로그램은 메모리에 올라가겠죠. 흔히 프로그램이 메모리에 로드(load)된다고 이야기합니다. 또한 해당 프로그램에서 사용하는 많은 변수들도 존재하겠죠. 이런 다양한 데이터들은 운영체제가 제공하는 메모리 공간에 올라가게 되는겁니다. 그리고 CPU는 이렇게 제공 받은 메모리 영역에 올라가져있는 데이터(코드)를 읽어가면서 프로그램을 실행하게 됩니다.

그렇다면 메모리 영역은 어떤식으로 구성이 되어있을까? 알아보겠습니다.

대표적으로 크게 4가지로 구성이 되어있는 메모리 공간을 살펴보겠습니다.

출처 : TCPSCHOOL.com

1. 코드 영역 | CODE

코드 영역이라는 말 그대로 프로그램의 코드가 올라가져 있는 영역입니다. 다만 우리가 작성한 프로그래밍 언어는 컴퓨터가 이해할 수 없기 때문에 기계어로 컴파일 되어 올라가져 있습니다.

2. 데이터 영역 | DATA

마찬가지로 데이터 영역이라는 말 그대로 데이터가 올라가는 영역입니다. 프로그램에서의 데이터이기 때문에 우리는 변수를 생각할 수 있겠네요.

즉, 변수가 올라가져 있는 영역입니다. 다만 프로그램이 실행되는 동안 항상 접근이 가능한 변수만 저장되어 있는데요. 다시 말해 전역 변수와 정적(static) 변수를 할당하기 위한 영역이라는 말입니다. 프로그램이 실행되는 동안 항상 접근이 가능하다는 의미는 프로그램의 시작과 함께 할당된다는 의미이기도 합니다. 그리고 프로그램이 종료되면 소멸한다는 의미도 되겠습니다.

3. 스택 영역 | STACK

push를 이용해 데이터를 저장하고 pop을 이용해 데이터를 제거하는 자료구조의 스택과 동일합니다. 후입선출(LIFO | Last In First Out)이라는 말이죠.

왜 스택을 사용할까요?? 다른 말로 왜 스택 영역이라는 말을 사용할까요?? 해당 영역은 데이터 영역처럼 변수를 위한 영역입니다. 하지만 다른 점은 함수의 호출과 관계되는 지역변수와 매개변수가 저장되는 영역이라는 겁니다.

위의 그림과 같이 설명을 하자면 스택 영역에 데이터들은 메모리의 높은 주소에서 낮은 주소의 방향으로 할당 받습니다. 가장 아래부터 위의 방향으로 차곡차곡 쌓인다고 볼 수 있는데요.

다른 예로 함수의 호출은 프로그램의 실행과 같다고 볼 수 있습니다. 그리고 함수들은 다른 함수를 호출할 수 있고 또 다른 함수 또한 다른 함수를 호출할 수 있습니다. 마치 push를 이용해 차곡차곡 쌓인다고 볼 수 있는데요.

호출된 함수의 처리가 완료되면 어떤가요? 해당 결과를 자신을 호출한 함수에게 반환하고 종료 되는데 이는 pop과 같습니다. 즉, 스택 영역은 함수의 호출로 할당(push)되고 함수의 호출이 완료될시에 소멸(pop)합니다. LIFO을 사용한다면 쉽게 데이터를 관리할 수 있겠죠. 그래서 스택 영역이라 부릅니다. 그리고 해당 영역에 저장되는 함수의 호출 정보를 스택 프레임(Stack Frame)이라 말합니다.

4. 힙 영역 | HEAP

힙 영역은 스택과 반대입니다. 메모리의 낮은 주소에서 높은 주소의 방향으로 할당이 되는데요.

마찬가지로 위의 그림을 보고 설명하면 위부터 아래 방향으로 내려가며 선입선출(FIFO | First In First Out)의 형태를 가지고 있습니다.

힙 영역의 특징은 사용자가 직접 관리하는 메모리 영역이라는 겁니다. 다시 말해 사용자에 의해 동적으로 메모리 공간이 할당되고 해제된다는 말인데요. C 언어의 malloc(), free() 등을 통해서 동적으로 생성(할당)하고 해제할 수 있겠네요. 그렇다보니 힙 영역은 런타임(runtime)에 의해 결정이 됩니다.

간단하게 보자면 아래와 같습니다.

  • code(text): 코드
  • data: 변수/초기화된 데이터
  • stack: 임시 데이터(함수 호출, 로컬 변수등)
  • heap: 코드에서 동적으로 만들어지는 데이터

낮은 주소 높은 주소의 얘기가 나오는데 해당 주소는 CPU의 구성이나 컴파일러가 어떤 방식으로 실행파일을 만드는지 등의 따라 반대가 될 수 있습니다.


데이터 영역의 BSS | Block Started by Symbol

BSS(Block Started by Symbol)

이미지 출처: wikipedia.org
이 영역은

  • 초기화 되지 않은
  • 초기화를 0으로 한
  • 초기화를 Null로 한 포인터
    정적변수 및 전역변수를 위한 영역이다.

    왜 초기값이 0이나 NULL이 아닌 값으로 설정된 data 영역과 이런 식으로 초기화를 하지 않은 변수들을 위한 공간을 따로 만들어서 구분이 필요한 이유는, 전체 프로그램의 크기를 작게 만들 수 있기 때문이다.

    대부분의 용량 걱정할 필요 없는 PC에 탑재되는 프로그램과는 달리 임베디드 시스템에 탑재되는 프로그램의 경우, 작은 ROM 안에 프로그램을 욱여넣어야 하는 경우가 많이 있는데 초기값이 주어진 data영역에 들어가는 변수들은 변수마다 값을 넣어주는 공간만큼 용량을 차지하지만, 초기화 되지 않은 bss에 들어가는 변수들은 그 값을 넣어줄 필요가 없기에 그냥 변수가 있다! 라고만 해 주면 된다. 따라서 변수의 값을 써 넣을 필요가 없으며 그만큼 프로그램의 용량이 작아지게 된다.

    프로그램 실행 시, crt0등에 의해서 bss가 확보된다. 출처: 나무위키

데이터 영역에는 BSS라는 영역이 있습니다. 위 설명이 너무 잘 나와있어서 위 글만 참고해보셔도 좋을 듯 합니다.


컨텍스트 스위칭의 핵심 PC(Program Counter), SP(Stack Pointer)

프로그램 카운터(Program counter, PC)

마이크로프로세서(중앙 처리 장치) 내부에 있는 레지스터 중의 하나로서, 다음에 실행될 명령어의 주소를 가지고 있어 실행할 기계어 코드의 위치를 지정한다. 때문에 명령어 포인터라고도 한다. 인텔의 x86계열의 CPU에서는 IP(Instruction Pointer)라고 한다. | 출처: 위키백과
간단하게 코드를 한줄한줄 가르키는 주소 레지스터라고 생각하면 됩니다.

스택 포인터(Stack Pointer, SP)

중앙 처리 장치(CPU)안에서 스택에 데이터가 채워진 위치를 가리키는 레지스터입니다. 스택의 데이터가 채워진 마지막 위치를 가르키며 다시 말해 스택의 특성상 스택 포인터가 가르키는 곳까지가 데이터가 채워져있는 영역이라 생각할 수 있고 그 이후부터 스택 끝까지는 데이터가 없는 영역이라고 생각할 수 있습니다. 즉, 스택에 새로운 데이터가 추가되거나 제거되면 스택 포인터의 값이 증가하거나 감소한다고 볼 수 있습니다.
간단하게 스택의 데이터가 채워진 마지막 위치를 가르킨다라고 생각하면 됩니다.

편하게 프로세서 A를 A, 프로세서 B를 B 라고 하겠습니다.

이렇게 위의 내용들을 이해했다면 컨텍스트 스위칭에 대해서 다시 보겠습니다. 컨텍스트 스위칭은 앞에도 이야기했지만 프로세서를 교체해주는 매커니즘이라고 이야기했습니다. 그렇다면 여기서 의문점은 A를 Running 상태에서 Ready로 교체하고 B를 실행하는건 이제 대충 이해할 수 있습니다.

그런데 B에서 다시 A로 돌아가야할때 A의 어디서부터 코드를 읽어야하는지 알아야 하는데, 그것이 가능한 이유는 PCB가 있기 때문입니다.

프로세스 제어 블록( PCB | Process Control Block )

특정한 프로세스를 관리할 필요가 있는 정보를 포함하는 운영 체제 커널의 자료 구조이다. 작업 제어 블록(Task Control Block, 줄여서 TCB) 또는 작업 구조라고도 한다. "PCB는 운영 체제가 프로세스를 표현한 것이다." | 출처: 위키백과

앞에 컨텍스트 스위칭의 핵심으로 PC와 SP를 말했는데요. 프로세서가 실행해야 하는 정보들이죠. 이러한 정보들을 PCB에 저장해놓기 때문에 CPU는 여러 프로세스를 돌아가며 실행하여도 어느 위치에서 실행을 해야하는지 알 수 있는겁니다.

PCB는 프로세스가 생성될 때마다 해당 프로세서만의 고유 PCB가 생성이 되기 때문에 많은 프로세서들이 있더라도 혼동 없이 실행할 수 있고 프로세서가 완료되면 해당 PCB는 제거가 됩니다.

또 어떤 정보를 가지고 있는지 살펴보자면 아래와 같습니다.

운영체제에 따라 PCB에 포함되는 항목이 다를 수 있지만, 일반적으로는 다음과 같은 정보가 포함되어 있다. 출처: 위키백과

  • 프로세스 식별자(Process ID)
  • 프로세스 상태(Process State): 생성(create), 준비(ready), 실행(running), 대기(waiting), 완료(terminated) 상태가 있다. - 유예준비상태suspended ready, 유예대기상태suspended wait 는 스택이 아닌 disk에 저장된다.
  • 프로그램 계수기(Program Counter): 프로그램 계수기는 이 프로세스가 다음에 실행할 명령어의 주소를 가리킨다.
  • CPU 레지스터 및 일반 레지스터
  • CPU 스케줄링 정보: 우선 순위, 최종 실행시각, CPU 점유시간 등
  • 메모리 관리 정보: 해당 프로세스의 주소 공간 등
  • 프로세스 계정 정보: 페이지 테이블, 스케줄링 큐 포인터, 소유자, 부모 등
  • 입출력 상태 정보: 프로세스에 할당된 입출력장치 목록, 열린 파일 목록 등

컨텍스트 스위칭을 정리하자면?

    1. 실행 중지할 프로세스 A의 정보를 프로세스 A 자신의 PCB(PC, SP)에 업데이트해서 메인 메모리에 저장합니다.
    1. 다음으로 실행할 프로세스 B의 정보를 메인 메모리에 있는 프로세스 B의 PCB 정보(PC, SP)를 CPU의 레지스터에 넣고 실행합니다.
    • 이때 Ready 상태의 프로세스를 Running 상태로 바꾸면서 PCB(PC, SP)정보를 CPU 레지스터에 넣어 실행하는 과정을 디스패치(Dispatch)라고 합니다.

전 포스팅에서도 얘기했지만 이러한 컨텍스트 스위칭도 실행해야하는 코드이기 때문에 당연히 실행하는데 시간이 필요합니다. 보통 10ms ~ 20ms의 시간이 필요하다고 알려져 있는데요.

당연히 이러한 컨텍스트 스위칭이 빈번하게 일어나면 오버헤드가 될 수 있기 때문에 리눅스 운영체제의 경우 컨텍스트 스위칭 코드를 어셈블리어로 작성하는 경우가 있다고 합니다. 이렇게 어셈블리어로 작성하면 컴파일에 필요한 시간을 아낄 수 있기 때문에 속도면에서 더 유리하겠지만 반대로 프로그램의 이식성이 떨어진다는 단점이 있다는것도 알고있으면 좋을 듯 합니다.

profile
자바스크립트를 좋아합니다. | 이유를 알고 있는 것과 모르는 것의 차이는 분명하다.

0개의 댓글