티스토리 뷰

반응형

안녕하세요 Pingu입니다!

 

이번 글에서는 운영체제에서 Process라고 불리는 것에 대해 알아보려고 합니다. 제가 공부할 때 참고하고 있는 OSTEP 책에선 Chapter 4 - Processes 부분입니다.

Process란?

Process(프로세스)가 무엇일까요? 프로세스는 간단하게 말하면 현재 실행 중인 프로그램이라고 할 수 있습니다. 그렇다면 프로그램은 무엇일까요? 프로그램은 Disk에 저장되어있는 실행 가능한 것이라고 볼 수 있습니다. 컴퓨터는 이러한 프로그램을 메모리에 Load 하고 이를 CPU에서 처리합니다. 이러한 동작들이 잘 수행될 수 있도록 OS는 어떤 일을 어떤 방법으로 수행 중인지 알아보도록 하겠습니다.

Multiple processes - 여러개의 프로세스를 동시에 동작시키는 방법?

그렇다면 이러한 프로세스를 우리는 어떻게 사용하고 있을까요? 만약 컴퓨터에서 한 개의 프로세스만 사용 가능하다고 생각해봅시다. 만약 검색을 위해 인터넷 브라우저를 실행하면 검색을 하는 동안 다른 프로그램은 실행할 수 없는 아주 불편한 상황이 발생할 수도 있게 됩니다. 그래서 OS는 여러 개의 프로그램을 동시에 실행할 수 있도록 CPU를 가상화하는 방법을 사용합니다. 이는 실제 물리적인 CPU는 1개뿐이지만 프로그램들에게는 마치 여러 개의 CPU가 있는 것 처럼하여 여러 프로그램을 동시에 사용할 수 있게 됩니다.

 

여기서 CPU 가상화 방법에 관해 설명드리기 전에 Mechanism과 Policy에 대해 간단히 이해하고 넘어가도록 하겠습니다. Mechanism은 필요한 기능을 구현하는 low-level 메서드나 프로토콜입니다. 즉 간단하게 말하면 어떻게 할 것이냐에 관한 것입니다. Policy(정책)는 Mechanism 위에 존재하는 정책으로 어떤 종류의 결정을 내리는 알고리즘입니다. 즉 무엇을 할 것이냐에 관한 것입니다.

 

그럼 이제 CPU 가상화를 통해 여러개의 프로그램을 동시에 실행하는 방법은 어떻게 하면 될까요? CPU가 사는 시간은 인간이 사는 시간과는 다릅니다. 인간에게 1초는 짧은 시간이지만 CPU에게 1초는 아주 긴 시간입니다. 만약 어떤 CPU가 1.0 GHz의 클럭 속도를 가진다면 이는 1초에 10^9개의 명령어를 수행하는 CPU라는 말이 됩니다. 즉 CPU에게 1초란 아주 많은 명령어를 수행할 수 있는 시간이 됩니다. 이렇게 CPU와 인간의 다른 시간 개념을 사용하는 Time-sharing 메커니즘을 사용하면 CPU 가상화를 할 수 있습니다. 예를 들어 1개의 CPU를 가진 컴퓨터 사용자가 A, B, C라는 3개의 프로그램을 동시에 실행하고 싶다고 하면 단순하게 하나의 프로그램을 0.001초 즉 1ms씩 수행 후 다른 프로그램을 수행하게 하는 방법이 Time-sharing 방법입니다. A를 0.001초 동안 실행한 뒤 B를 0.001초 동안 실행하고 C를 0.001초 동안 실행한 뒤 다시 A를 0.001초만큼 수행하는 방식으로 프로그램을 수행하게 되면 사용자는 마치 프로그램이 동시에 동작하고 있는 것처럼 보게 됩니다. 여기서 A가 수행되다 멈추고 B를 수행하게 되는데 만약 다시 A가 수행될 땐 이전에 멈춘 부분부터 수행하게 해주는 메커니즘은 Context-Switch라고 합니다.

 

이번에는 CPU 가상화를 위한 Policy(정책)를 알아보겠습니다. CPU 가상화를 위한 정책에는 Scheduling 정책이 있습니다. 아까 Time-sharing과 같은 메커니즘에서 사용자는 마치 프로그램이 동시에 실행되는 것 처럼 보이지만 실제로는 동시에 일어나지 않습니다. 위의 예에선 0.001초씩 번갈아가며 실행되기 때문에 CPU입장에선 어떤 프로세스를 먼저 실행할지 고민이 될 수 있습니다. 이러한 고민을 해결해주는 것이 Scheduling 정책입니다. Scheduling 정책으로 CPU가 지금 어떤 프로세스를 실행하면 되는지 알려줄 수 있게 됩니다. 이번에 알게 된 Time-sharing, Context-Switch, Scheduling은 후에 다시 자세히 알아보도록 하겠습니다.

Process Structure

이러한 프로세스를 OS가 관리하기 위해서 Process Structure를 사용합니다. 우선 프로세스는 CPU, Memory, I/O 정보를 필요로 합니다. 구체적으로는 CPU에서는 register(레지스터)를 필요로 하며 여기엔 Program Counter, Stack Pointer 등이 있습니다. Memory에서는 주소 공간을 필요로 합니다. 여기서 필요한 주소공간을 그림으로 나타내면 다음과 같습니다.

 

 

 

프로세스는 위와 같은 주소 공간을 필요로 하게되며 stack은 위에서 아래로 커지고 heap은 아래에서 위로 커지는 방식입니다. 각 부분 별 정보는 위의 그림에서 참고하시길 바랍니다. 프로세스는 기본적으로 3가지 I/O를 가지게 되며 이는 input, output, error입니다. 이에 관해서는 persistence 단원에서 자세히 알아보도록 하겠습니다.

 

Process API

이러한 프로세스를 사용하기 위해 많은 API가 있지만 OS마다 종류가 다를 수 있습니다. 그러므로 여기에서는 모든 OS에서 공통적으로 가져야 하는 API에 대해 살펴보겠습니다.

  • Create
    • 새로운 프로세스를 만듭니다.
  • Destory
    • 프로세스를 제거합니다.
  • Wait
    • 프로세스가 실행 중 잠시 멈출 일이 생길 때 사용합니다.
  • Miscellaneous Control
    • 잘못 동작하고 있는 프로세스를 종료할 때 사용합니다.
  • Status
    • 프로세스ID, 프로세스가 얼마 동안 실행됐는지 등에 대한 상태에 대한 정보를 알고 싶을 때 사용합니다.

이는 다음 포스팅에서 살펴보도록 하겠습니다.

 

프로그램을 실행시키는 방법

그럼 이제 프로그램을 실행시켜 프로세스로 만드는 방법에 대해 좀 더 자세히 알아보도록 하겠습니다. 우선 간단히 단계적으로 나타내면 다음과 같습니다.

 

  • Load
  • Dynamic allocation
  • Initialization
  • Jump to entry point : main()

단계별로 차례대로 살펴보겠습니다. 먼저 Load 단계에서는 말 그대로 Disk에 있는 프로그램을 DRAM과 같은 메모리에 프로세스로 적재시키는 것입니다. 예전에 만든 OS는 프로그램이 실행되기 전에 이러한 로드 작업을 한 번에 수행했는데 요즘에 만들어지는 OS는 프로그램 실행에 필요한 데이터만 로드합니다. 이러한 것은 paging, swapping 방법으로 가능하게 됐으며 이는 나중에 자세히 다루도록 하겠습니다. 또한 이렇게 프로그램을 로드하기 위해서는 디스크상에 존재하는 프로그램의 형식을 정확하게 알아야 하는데, 리눅스에서는 ELF 포맷, 윈도우에서는 PE 포맷과 같은 형식이 있습니다.

 

Dynamic allocation 단계에서는 메모리에 적재된 프로그램의 데이터를 아까 위에서 본 그림처럼 배치합니다. Stack공간에는 지역변수, 함수 매개변수 그리고 return address를 저장합니다. Heap 공간에는 동적 할당 하는 데이터가 저장되며 이는 C언어에서 malloc(), free()로 관리할 수 있습니다.

 

Initialization 단계에서는 미리 처리되어야 할 file descriptor(input, output, error), I/O와 같은 부분을 처리하게 됩니다.

 

위의 모든 준비가 마치면 OS는 프로그램을 실행할 준비가 된 것으로 판단하고 시작지점으로 점프하게 됩니다. 시작 지점이라는 것은 C언어에서는 main() 함수가 됩니다.

Process States

그럼 이제 프로그램을 실행시켜 프로세스로 만드는 방법도 알았으니 실행된 프로세스의 상태에 대해 알아보겠습니다. 우선 프로세스 상태에는 크게 3가지가 있으며 이는 Running, Ready, Blocked 상태입니다. 그럼 각각의 상태에 대해 알아보겠습니다.

 

 

 

  • Running (실행 중)

    • Running 상태는 프로세스가 프로세서에 의해 실행되고 있는 상태를 말합니다. 즉 실행중인 명령을 뜻하는 것이죠.
  • Ready (준비 완료)

    • 아까 위에서 본 프로그램을 프로세스로 만드는 방법을 모두 수행해서 이제 실행할 준비가 된 상태입니다. 하지만 아직 OS의 스케줄링 정책에서 선택 받지못해 실행은 되지 않은 상태라고 볼 수 있습니다.
  • Blocked (대기)

    • 프로그램을 실행 중 먼저 실행해야하는 것이 생기거나 I/O 요청이 들어오면 실행중인 프로세스를 잠깐 멈출 수 있는데 그렇게 멈춰진 상태를 뜻합니다.

이제 막 실행될 준비가 완료된 프로세스는 Ready 상태로 대기하게 됩니다. 만약 OS의 스케쥴링 정책에 의해 자신이 실행될 차례가 되어 dispatch 되는 것을 Scheduled라고 합니다. 그러다 만약 I/O가 발생하거나 다른 프로세스를 먼저 실행해야 하는 경우가 생기면 Blocked 상태가 되고 해당 이슈를 해결하면 다시 Ready상태가 되어 스케쥴링되기를 기다립니다. 실행 중 Time-sharing 기법에 의해 주어진 실행시간이 끝나게 되면 Ready상태로 다시 돌아가게 됩니다. 하지만 만약 프로세스가 더 이상 할 일이 없어지게 되면 Running에서 종료 상태가 되어 프로세스가 끝나게 됩니다.

 

Process States Examples

그럼 이번엔 예제를 통해 프로세스 상태를 이해해보도록 하겠습니다.

 

 

위의 예를 보게 되면 프로세스는 총 2개(Process0, Process1)가 존재합니다. 1~4초까지는 Process0이 스케줄링되어 Running 상태인 것을 볼 수 있습니다. 4초에 할 일이 끝나게 되어 프로세스가 종료되고 OS의 스케줄러는 Process1을 스케줄링하여 프로세스 상태가 Ready에서 Running 상태로 변하게 됩니다. 8초에는 Process1까지 실행을 끝내고 프로세스를 종료하게 됩니다.

 

 

위의 예는 프로세스가 2개인 것과 처음에 스케줄링이 된 프로세스가 Process0인 것은 동일합니다. 하지만 4초에서 I/O가 발생하여 Process0이 Blocked 상태가 되고 Process1이 실행되게 됩니다. 그런 뒤 쭉 Process1을 수행하다 7초에서 Process0을 Blocked 상태로 만든 I/O가 완료되어 이제 다시 Process0이 Ready 상태가 되지만 Process1이 실행 중이기 때문에 계속 Ready상태를 유지합니다. 8초에서 Process1이 실행을 마치고 종료되면 다시 Process0가 실행을 하고 완료되면 종료하게 됩니다.

 

Process Control Block

그럼 이번엔 프로세스를 관리하기 위해 필요한 정보들을 저장하는 Process Control Block을 알아보겠습니다. PCB는 하나의 자료구조로 각각의 프로세스가 하나씩 가지고 있습니다. PCB에는 프로세스 상태, 프로세스 ID, Program Counter, 메모리 관리 정보, CPU 스케줄링 정보, 등이 저장되어있으며 Context Switch에 사용되는 정보도 저장됩니다.

 

 

 

위의 코드는 프로세스 구조를 나타낸 코드입니다. proc 구조체의 속성 중 struct context context; 부분이 context switch에 사용되는 부분입니다. 위의 구조를 사용하면 프로세스가 종료 후에 메모리에서 제거하지 않을 수도 있는데 이러한 상태를 좀비 상태라고 합니다. 이는 보통 부모 프로세스가 자식 프로세스가 끝나기를 기다릴 때 사용할 수 있습니다.

 

이번 글 마무리

이렇게  프로세스가 무엇이고 CPU 가상화를 통해 여러 프로세스를 동시에 실행하는 것처럼 보이게 할 수 있다는 것을 알았습니다. 또한 프로세스가 어떻게 동작되는지 실행에 필요한 것은 무엇인지도 알 수 있었습니다. 

 

다음 글 : Limited Direct Execution 메커니즘이란?

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함