프로그램과 프로세스의 개념

쓰레드를 먼저 알기 전에 프로그램과 프로세스의 개념을 알아보자.

프로그램이란 디스크 내의 실행 가능한 파일을 말하며,
프로세스란 현재 실행 중인 프로그램을 말하며 태스크(task)라고도 부른다.
프로세스는 시스템 작업의 기본단위로 모든 운영체제는 프로세스 개념을 바탕으로 동작한다.
그리고 이 프로세스를 구성하는 요소들을 프로세스의 문맥(process contexts)라고 한다.

예를 들어, 윈도우 환경에서 엑셀 프로그램이 있을 때 이를 실행하여 엑셀창(윈도우)를 띄우면 이는 프로세스가 된다.

  • 특징
    • 프로세스는 각각 독립된 메모리 영역(Code, Data, Stack, Heap의 구조)을 할당받는다.
    • 기본적으로 프로세스당 최소 1개의 스레드(메인 스레드)를 가지고 있다.
    • 각 프로세스는 별도의 주소 공간에서 실행되며, 한 프로세스는 다른 프로세스의 변수나 자료구조에 접근할 수 없다.
    • 한 프로세스가 다른 프로세스의 자원에 접근하려면 프로세스 간의 통신(IPC, inter-process-communication)을 사용해야 한다.
      ex) 파이프, 파일, 소켓 등을 이용한 통신 방법 이용

프로그램이 실행되면 위 그림과 같이 메모리 공간에 프로세스가 존재한다.

  • stack : 지역변수 할당과 함수 호출 시 전달되는 인자값들을 저장하기 위한 공간
  • heap : C의 malloc, calloc와 C++,Java의 new를 통한 동적 할당을 위해 존재하는 공간
  • data : 전역 변수나 static 변수의 할당을 위해 존재하는 공간
  • code : 프로그램을 실행시키면 실행파일 내에 존재하는 명령어가 메모리 상에 올라가야 프로그램을 동작시킬 수 있다. 이 명령어들을 위해 존재하는 공간(쉽게 말해 소스코드가 올라간다고 생각하면 됨)

이렇게 프로그램을 실행시키기 위해서는 메모리에 process를 위한 공간이 필요하다. 메모리 공간을 기준으로 process를 살펴본 결과이다. 이는 나중에 쓰레드와 비교할때에도 중요한 의미를 갖는다. 특정 프로그램이 실행되기 위해서는 즉, process가 되려면 메모리에 위 그림과 같은 할당이 필수적으로 이루어져야 한다. 메모리가 할당된 다음에 CPU에 의해서 처리된다.

여기서 프로세스의 문맥이란 무엇을 말하는가?

  1. CPU 수행 상태를 나타내는 하드웨어 문맥. Program Counter 등의 register들 값을 포함한다.
    PC는 다음에 수행할 명령어의 위치에 대한 정보(주소값)을 담고 있다.
    CPU가 할당되었을 때, PC가 가리키는 부분부터 수행해나가면 되는 것이다.
    즉, 프로세스가 실행될 부분이라고 생각할 수 있다.
  1. 프로세스의 주소 공간을 포함한다.
    즉, code, data, stack 각각의 공간에 어떠한 값이 들어있는가를 나타내는 주소값을 포함한다.
    현재 변수의 값을 얼마인가? 메모리에는 어떤 내용들이 담겨져 있는가? 스택에는 어느 내용까지 쌓여있는가? 등에 대한 정보를 모두 담고 있다.
  1. 프로세스 관련 커널 자료구조를 포함한다.
    PCB(Process Control Block), Kernel Stack 등을 포함한다.
    프로세스가 하나 시작될 때마다 운영체제에서는 그 프로세스를 관리하기 위해 PCB를 생성한다.
    커널의 주소 공간에서 data에 해당하는 부분에 PCB를 저장해둔다.
    이는 운영체제가 이 프로세스를 어떻게 관리하는지, 어떻게 다루고 있는지 파악할 때 사용된다.
    시스템 콜이 발생할 때, 어떤 프로세스가 시스템 콜을 했는지 알기 위해 커널 주소 공간의 Stack에는 시스템 콜을 한 프로세스의 커널 스택 값을 저장하고 있다.

운영체제가 문맥(context)을 알고 있어야 하는 이유

현재의 컴퓨터는 time sharing, multitasking 체제이다. 즉, 하나의 CPU가 여러 개의 프로세스를 동시에 수행한다. 짧은 속도로 여러 개의 프로세스를 수행해야 하는 CPU의 입장에서는 이전에 수행하고 있던 프로세스가 어디까지 진행되었는지를 알아야 할 필요가 생긴다.(그래야 효율적이다.) 그 어디까지 진행되었는지에 대한 값을 문맥 즉, context에 저장하고 있기 때문에 이 문맥을 CPU가 알고 있어야 한다.

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

프로세스 제어 블록이란 프로세스를 관리하기 위해 필요한 프로세스 요소들의 자료구조이다.

운영체제가 현재 CPU 제어권을 다른 프로세스에게 넘겨줄 때 실행중인 프로세스의 정보를 PCB에 저장한다. CPU 제어권을 다시 넘겨받은 경우 PCB에 저장되어 있던 정보를 불러와 추후 작업을 실행한다.

PCB는 주로 다음과 같이 구성된다.

  • 프로세스 식별자(Identifier)
  • 프로세스 상태(State)
  • 우선순위(Priority)같은 스케줄링에 대한 정보
  • 메모리 포인터(Memory pointer)
  • CPU 수행에 관련된 프로그램 카운터(Program counter), 각종 register 값
  • I/O 상태정보(I/O status information)
  • code, data, stack에 대한 정보

프로세스 상태

프로세스는 실행되면서 자신의 상태가 시시각가 변한다.

  • 생성(New) : 프로세스가 생성 중
    • 프로세스가 생성되었지만 실행가능한 프로세스 집합에 소속되지 못한 상태(프로그램이 메모리에 적재되지 않은 상태)
  • 준비(Ready) : 프로세스가 설정되어 대기중
    • CPU를 할당받기 위해 준비중인 상태(즉 Queue에서 대기하고 있는 상태를 의미한다. 이는 물리적인 메모리에 적재된 상태를 말한다.)
  • 실행(Running) : 프로세스가 실행하는 중
    • 프로세스가 CPU를 할당받아 기계어 명령어를 수행중인 상태
  • 대기(Block, wait, sleep) : 프로세스가 어떤 사건이 발생하기를 기다리고 있는 상태
    • 당장 CPU를 할당해줘도 instruction을 수행할 수 없는 상태를 말한다. 디스크에서 file을 읽어와야 하는 오래 걸리는 작업을 하고 있거나 다른 프로세스의 진행을 위해 일부러 재워둔 경우에 해당한다.
  • 종료(Exit) : 프로세스가 실행 종료
    • 프로세스가 실행 종료된 상태(프로그램이 메모리에서 해제된 상태) 프로세스가 종료되면 정리하는 작업을 진행하게 되는데 이 상태에 해당한다.

프로세스 상태 전이

프로세스는 아래와 같은 상태 전이를 가지며 주로 아래와 같이 명명한다.

  • 디스패치(Dispatch) : 준비 -> 실행
  • 타임 아웃(Time out) : 실행 -> 준비
  • 대기(block) 또는 사건 준비(Event Wait) : 실행 -> 대기
  • 깨움(wake up) 또는 사건 발생(Event Occurs) : 대기 -> 준비
  • new -> ready : new 상태에서 프로세스가 생성되면 OS 커널에 존재하는 Ready Queue에 올라가게 된다.
  • ready -> running : Ready Queue에 있는 프로세스들을 OS가 프로세스 스케쥴링 알고리즘에 의해서 Running 상태로 가야할 프로세스에게 CPU를 할당한다. 그러면 프로세스가 Running 상태가 된다.
  • running -> ready : 현재 running 상태에 있는 프로세스 A보다 Ready Queue에서 대기하고 있는 프로세스 B가 우선순위가 높으면, preemptive schedule(선점형)인 경우 프로세스 A는 Ready 상태로 오게 되고 프로세스 B가 Running 상태가 되어 CPU를 할당 받게 된다.
  • running -> blocked : 현재 running 상태에 있는 프로세스 A에게 입출력(I/O) 이벤트가 발생했을 때 프로세스 A가 blocked 상태로 가게 된다.
  • running -> terminate : 프로세스 종료.

Context Switch(문맥 교환)

문맥 교환이란 CPU를 어떤 프로세스에서 다른 프로세스로 넘겨주는 과정을 말한다. System call이나 interrupt가 발생헀다고 해서 반드시 Context Switch가 발생하는 것은 아니다. 프로세스 내부에서 System call을 요청하거나 interrupt가 외부에서 들어왔어도 운영체제에서의 일을 마치고 다시 할당되었던 CPU로 넘어가게 된다.
다른 프로세스로 넘어가는 과정은 상당한 오버헤드를 발생시킨다.
cache memory에 있던 진행하던 프로세스에 대한 cache를 모두 비워줘야 하기 때문이다. 그래서 문맥 교환이 일어나는 상황은 크게 두 가지 경우이다.

Interrupt 중에서도 timer interrupt가 들어왔을 때와 I/O 요청 System Call이 들어왔을 때이다.

전환하는 동안에는 어떠한 유용한 작업도 불가능하다.

IPC

준비중.

참고