[운영체제/OS] 프로세스와 컨텍스트 스위칭(Context Switching)
kindof
·2021. 6. 14. 19:48
0. 들어가면서
프로세스(Process)는 개발을 하는 사람들이 가장 많이 들어보는 단어 중에 하나라고 생각합니다.
사실 개발을 하는 사람 뿐만 아니라, 일상 생활에서도 프로세스라는 말은 참 많이 쓰죠.
그런데 과연 '프로세스'란 정확히 무엇을 의미할까요?
1. 프로세스(Process)
Process: A process is a program in execution which then forms the basis of all computation.
위 정의처럼 프로세스는 실행 중인 프로그램을 의미합니다. 그렇다면, 실행 중인 프로그램이라는 것은 도대체 무엇으로 구성되어 있을까요?
프로세스는 크게 이미지(Image) 영역과 컨텍스트(Context) 영역으로 구분되어 있습니다. 프로세스의 컨텍스트 영역에는 Data Reigster, $PC, $SP 등의 값이 저장되고, 프로세스의 이미지 영역에 우리가 흔히 말하는 스택, 힙, 데이터, 코드 영역이 존재합니다.
아래 그림을 통해 프로세스의 이미지 영역을 자세히 들여다 보겠습니다.
프로세스의 이미지(Image) 구조는 위와 같습니다. 제일 작은 메모리 주소 부분에는 Text(Code) 영역이 존재하는데, 여기에는 실행 가능한 코드들이 컴파일한 기계어 형태로 저장됩니다.
그리고 그 위에는 초기화해서 변하지 않는 변수를 저장하고, 다시 그 위에 아직 초기화하지 않은 전역 변수나 정적(static) 변수를 저장합니다. 이 두 부분을 엄밀히 구분할수도 있는데, 여기서는 Data 영역으로 표시되어 있습니다.
Stack 영역에는 지역 변수, 임시 변수, 매개 변수, return value, return address 등이 저장됩니다. 여기서 return address란 어떤 함수를 호출하고 그 결과를 다시 main이나 다른 함수에 return해야 할 때, 돌아갈 곳을 명시해주는 주소를 담는 공간입니다.
참고로 Stack 영역은 컴파일 타임에 크기가 결정되기 때문에 무한히 할당할 수가 없습니다. 때문에 재귀함수가 너무 많이 호출되거나 함수가 지역변수를 너무 많이 가지고 있어서 Stack 영역을 초과하게 되면 StackOverflow에러가 발생하기도 하죠.
Heap 메모리 영역에는 프로그램 런타임에 동적 메모리가 할당됩니다. 쉽게 말해 이 영역에는 객체의 데이터가 저장된다고 볼 수 있는데요. 스택 영역에는 이 객체들에 대한 참조값이 저장되어 있어서 이를 통해 힙 영역에 존재하는 객체에 접근할 수 있게 됩니다.
스택 영역과 힙 영역에 대해서는 JVM의 GC를 설명할 때 자세히 다룬 적이 있어서 참고하실 분은 아래 링크를 확인해보시면 좋겠습니다.
💡 2. PCB(Process Control Block)
위에서 우리는 프로세스를 실행 중인 프로그램이라고 했습니다. 그런데 이를 조금 다르게 정의해보면 프로세스는 곧 실행 가능한 PCB(Process Control Block)를 가진 프로그램이라고 볼 수도 있는데요.
PCB는 운영체제가 프로세스를 제어하기 위해 정보를 저장해 놓는 곳으로 프로세스의 상태 정보를 저장하는 구조체라고 생각하면 됩니다.
프로그램을 돌아간다는 것은 많은 수의 프로세스가 돌아간다는 것을 의미합니다. 그리고 이러한 프로세스들은 Time Sharing을 하거나 서로 참조하는 등으로 컨텍스트 스위칭(Context Switching)을 하게 되는데, 이를 위해서 각 프로세스의 상태를 저장할 공간인 PCB가 필요한 것입니다.
PCB는 아래 그림과 같은 구조로 생겼습니다.
Process ID는 프로세스의 고유 번호를 의미하며 Process State는 프로세스의 준비, 대기, 실행 등의 상태 정보를 가지고 있습니다.
Process Counter(Pointer)는 프로세스가 다음에 실행할 명령어의 주소를 저장하고 있으며 Register information은 레지스터는 메모리 연산을 처리하기 위해서 임시로 가지고 있는 기억 공간인데 CPU옆에 붙어 있습니다.
Scheduling information은 자신이 CPU스케쥴링에서 어떤 우선 순위를 가지고 있는지에 대한 정보이며 Memomry related information은 할당된 자원의 정보를 가지고 있죠.
또한 Accounting information에는 프로세스를 처리하고 있는 CPU의 사용시간, 실제 사용된 시간 등이 담겨있으며 Status information related to I/O는 입출력 상태 정보를 가지고 있습니다. 프로세스에 할당된 입출력장치의 목록이나 열린 파일 목록 등을 저장하고 있죠.
이렇게 PCB에는 프로세스별로 고유한 값들이 저장되어 있고, 이 값들을 바탕으로 여러 프로세스들을 오가며 전체적인 프로그램이 작동하게 됩니다.
위 PCB의 구조를 하나하나 외우지는 말고 프로그램이 돌아가는 데 프로세스들의 개별 정보가 담겨있다고 이해하면 될 것 같습니다.
3. Context Switching
3-1. 왜 필요한가?
Context Switching은 한 개의 CPU가 하나의 프로세스만 처리할 수 있기 때문에 필요해진 개념입니다.
CPU가 하나의 프로세스를 끝날 때까지 계속 처리하고, 그 다음에서야 다음 프로세스를 처리할 수 있다면 프로세스들 간의 참조도 이루어질 수 없고, 프로세스 간 병목 현상도 심화됩니다.
따라서, CPU는 실행 중인 프로세스를 계속해서 변화시키는데 이 과정을 컨텍스트 스위칭(Context Switching)이라고 합니다.
3-2. 어떻게 이루어지는가?
위에서 살펴봤듯이, PCB는 Process Counter에 다음에 실행할 프로세스의 주소를 가지고 있는데요. Context Switching이 발생할 때는현재 프로세스의 PCB에서 다음 프로세스의 PCB를 찾아서 레지스터에 적재하고, CPU가 이전에 진행했던 과정을 이어서 진행하게 됩니다.
그런데 프로세스는 각 독립된 메모리 영역을 할당받았기 때문에 공유하는 메모리가 존재하지 않습니다.
따라서 Context Switching이 발생할 때 (1) 캐시 초기화, (2) 메모리 매핑 초기화, (3) 커널 모드로의 진입이라는 세 가지 비용을 항상 수반하게 되고, 이로 인해 큰 오버헤드가 발생하게 됩니다.
이 후 포스팅에서 살펴볼 멀티쓰레딩은 메모리 영역의 공유를 통해 Context Switching 오버헤드를 줄일 수 있기 때문에 더 빠른 응답 시간을 제공할 수 있게 됩니다.
4. 프로세스의 상태(Status)
한편, 우리의 프로그램은 여러 프로세스를 동시에 처리해야 하기 때문에 프로세스는 실행되는 동안 아래 그림처럼 계속해서 상태가 변합니다.
프로세스가 생성된 상태(New), CPU를 할당받기 위해 준비중인 상태(Ready), 어떤 이벤트를 기다리고 있는 상태(Blocked(Waiting)), Instruction(명령어)가 실행되고 있는 상태(Running), 종료 상태(Terminated)가 있죠.
예를 들어보겠습니다. 이전 시간에 인터럽트에 대해 공부했었는데요. 우리가 System Call을 호출하면 해당 프로세스는 Blocked 상태로 변하고 OS는 커널 모드로 진입하게 됩니다. 그러면 그동안 CPU는 다른 Process를 돌리고 있습니다. System call을 호출하는 동안 CPU가 아무일도 하고 있지 않으면 낭비이기 때문이죠.
시간이 지나 System operation이 끝나면 다시 CPU에게 Interrupt를 발생시킵니다. Interrupt를 받은 CPU는 현재 실행 중인 프로세스를 멈추고, 커널 모드로 돌아가 Interrupt를 Handling하죠. 그리고 이전 프로세스를 다시 Ready 상태로 돌려놓습니다. Ready 상태의 프로세스는 우선 순위나 CPU 점유 상태에 따라 다시 Running 상태로 될 준비를 하죠.
이러한 내용을 그림으로 정리해보면 아래와 같습니다.
프로세스가 Ready Queue에 들어와서 다시 재가동되는 것은 CPU 스케줄링에 의해 좌지우지되는 내용인데요. 이 부분에 대해서는 CPU Scheduling에 관한 글에서 설명하겠습니다.
5. Mode Switching VS Context Switching
한편, 이전 글에서 공부했던 것처럼 유저모드~커널모드 간의 스위칭은 세 가지 상황에서 일어납니다.
1. Hardware Externel interrupt(Timer, I/O Interrupt)
2. Software Exception(Page fault, invalid operations..)
3. System Call(I/O Operation, fort()..)
그리고 이렇게 유저모드와 커널모드 간의 스위칭 과정을 모드 스위칭(Mode Switching)이라고 하는데요. 모드 스위칭은 위에서 살펴본 프로세스 간의 Context Switching과는 다른 개념입니다.
모드 스위칭이 일어날 때는 현재 프로세스의 상태를 저장하고, 프로그램 카운터(PC)를 다음 작업을 할 주소값으로 세팅합니다. 그리고 커널 모드로 전환하여 수행해야 하는 Instruction을 핸들링하죠.
한편 Context Switching에서는 진행 중이던 프로세스의 상태를 기록하고, 불러오는 프로세스의 이전 상태를 복원해야 합니다. 또한 각 프로세스를 저장할 큐의 메모리 위치를 선점하는 등의 작업이 필요하죠. 즉, 프로세스의 상태를 변화시키는 과정 전체를 의미하기 때문에 모드 스위칭보다 조금 복잡합니다.
그리고 Context Switching은 모드 스위칭의 결과로 발생합니다. 즉, 인터럽트(Interrupt), Exception, System Call 등이 일어나면 Mode Swtiching이 일어나고 이에 따라 필요 시 Context Switching이 일어나는 것이죠.
그럼 Context Switching의 과정을 살펴볼까요? 위에서 살펴본 PCB 구조와 프로세스 상태 변화 그림을 같이 보겠습니다.
1. Context Switching이 일어나면 다른 프로세스로 넘어가기 위해 프로그램 컨텍스트(Program Context)를 바꿉니다.
2. 그리고 현재 프로세스의 상태(Running)를 blocked, ready, exit 등으로 바꿉니다.
3. Process Control block(PCB)를 적절한 큐로 이동시킵니다.
4. 프로세스 스케쥴링에 따라 다음에 수행할 프로세스를 선정합니다.
5. 수행할 프로세스의 PCB를 적절한 큐로 이동시킵니다.
6. 수행할 프로세스의 Process State를 Running으로 변환합니다.
7. 수행할 프로세스의 이전까지 작업했던 Program context를 복원하고 작업을 수행합니다.
위와 같은 방식으로 프로세스의 스위칭이 일어나게 됩니다. 이해가 되셨나요?
이렇게 이번 시간에는 프로세스란 무엇인지부터 프로세스의 구조와 PCB, 프로세스의 상태 및 스위칭 과정에 대해 살펴봤습니다.
다음 시간에는 본격적으로 OS가 어떻게 동작하는지 알아보도록 하겠습니다.
감사합니다.
'CS > OS' 카테고리의 다른 글
[운영체제/OS] 멀티쓰레드 구현해보기 (0) | 2021.06.14 |
---|---|
[운영체제/OS] 프로세스 모델의 한계과 멀티쓰레드의 필요성 (0) | 2021.06.14 |
[운영체제/OS] OS 자체는 어떻게 구현할까? (0) | 2021.06.14 |
[운영체제/OS] 가상머신(Virtual Machine)과 Linux OS에 대해 (0) | 2021.06.14 |
[운영체제/OS] 운영체제의 이중 동작 모드(Dual Mode Operation)와 인터럽트(Interrupt) (0) | 2021.06.14 |