본문 바로가기
학교 수업/운영체제

운영체제 || 4. Process

by Godgil 2021. 3. 19.

오늘은 프로세스에 관해서 포스팅 할거야.

윈도우 쓰는 사람 중에 ctrl + alt + del 안눌러본 사람 있을까?

 

프로그램이 말을 안들어서 강제 종료할때 자주 쓰지

여기 보면 프로세스라는 탭이 있어. 그리고 목록들을 보면, 내가 실행해놓은 그리고, 이미 실행되어있는 프로그램들의 목록이 보여.

 

자, 대충 감이 오지?

프로세스는 이미 실행중인 프로그램을 말해.

프로그램은 디스크상에 저장되어있는 단순한 파일이야.

 

또 다른말로, 프로세스는 현재 실행중인 프로그램의 인스턴스라고 볼 수 있어

 

우리가 OOP를 할 때 보면, 한 클래스에 여러 오브젝트를 만들 수 있지? 여기서도 마찬가지로, 한 프로그램에 여러 프로세스가 있을 수 있어. 그리고 오브젝트들은 각각 고유한 이름(변수명)을 가지듯이, 프로세스도 고유한 이름인 Process ID를 가져. 이건 중복될 수 없어. 중복되려면 OS에 의해 회수되고 난 뒤에 다시 그 ID를 사용할 수 있지.

 

 

1학년때 C언어를 배울때, 메모리의 구조에 대해 배웠을거야. 아래 그림을 보자

각 프로세스는 각자 독립된 주소영역을 가져, 즉, 모든 프로세스가 각자의 메모리 영역을 가지는거야.

 

Code영역에는 프로그램의 코드가 저장된, 가용되는 모든 instruction이 저장 돼.

Data 영역에는 전역변수가 저장이 돼

Heap영역에는 기본적으로 동적할당을 할 수 있는 영역이고

마지막으로 Stack 영역은 함수 호출시 임시로 사용되는 지역변수, 파라미터, 호출 후 돌아갈 코드 주소가 저장이 되어있어.

여기서 중요한점은

Heap과 Stack은 경계의 구분이 없이 증가될 수가 있어, 만약 스택이 힙을 넘어가는 상황이 오면 그 상황을 스택오버플로우라 그래. 엄청 많이 들어봤지?

heap영역을 넘어간다는 판단은 우리 CPU레지스터에 Stack Pointer가 있는데, 얘는 항상 Stack의 Top을 가리키거든, 얘가 판단할 수 있어

 

또, 프로세스 상태에 대해 얘기해 볼거야. 프로세스는 Event를 받게되면 다른 상태로 넘어가는 방식이거든? 

위와 같은 방식이야.

먼저 new()를 통해 새로운 프로세스가 생성되면 OS가 admittetd을 해 줄거야. OS는 이 프로세스 승인하고 나서, OS내부에 있는 Ready queue에 집어넣어. 여기에는 CPU의 점유율을 기다리는 프로세스가 특정한 순서로 대기하고 있는 상태야. 즉, 프로세스 상태는 Ready, 프로세스가 CPU를 점유할 준비가 된 상태로 기다리는거지.

 

여기서, CPU의 스케쥴러에 의해 자신의 차례가 되면 CPU를 점유하면서 running상태가 되는거야. 여기서는 주기적으로 Timer 인터럽트가 일어나거든? 타이머는 일정시간이 되면 시스템콜을 호출해서 다음 프로세스로 CPU점유를 넘겨주는 역할을 해, 이를 Context Switching이라고 불러. 이 타이머에 의해서 실행상태가 되기도하고, 준비상태가 되기도 해

 

실행하는 와중에 비동기적으로 I/O 입출력이나, Event 대기라는 인터럽트가 발생하면 어떻게될까? Event wating을 기다리면서 CPU를 계속 점유하고있으면 너무 비효율적이란 말이지. 그래서 여기서는 OS가 wating Queue에다가 프로세스를 집어넣어. 이 때 상태를 Wating상태라 그래, 이 큐에는 I/O이벤트, 시스템 이벤트를 기다리는 프로세스가 들어 가 있어.

 

마지막으로 exit()이라는 명령어를 사용해서 종료를 하게되면, OS는 그 프로세스에 가용된 자원을 회수할거야.

 

이게 전체적인 흐름도야.

 

 

프로세스는 또 계층구조를 가질 수 있어.

기본적으로 한 프로세스는 다른 프로세스를 만들 수 있거든? 이때 생성된 프로세스를 child process라 그래.

프로세스가 다른 프로세스를 생성하면 System Call을 사용하는대, 이때 사용되는 명령이 fork()명령이야.

그냥 프로세스 자신을 그대로 복제하는거야, 만들어진 프로세스는 권한이나 리소스를 상속받게 되는데, 하지만 PID는 다르게 생성이 돼.

 

이때 생성한 프로세스는 parent process라 하는데, 부모가 자식이 끝날때까지 기다릴 수도 있고? 같이 함께 실행 될 수도 있어.

 

fork()를 사용한 예제를 좀 볼까?

실행 결과는? 당연히 Hello world가 두번 출력이 될거야, 부모 프로세스가 먼저일지 자식이 먼저일지는 정확히 알 수 없어

 

얘는 어떻게 될까? 

이렇게, 만들어진 자식도 fork를 호출하면서 8번의 hello가 출력이 될거야.

 

또 다른 명령으로는 exec() 명령이 있어.

얘는 현재 프로세스의 이미지를 새거로 바꾸고 싶을때 사용해. 즉, fork()는 새로 하나 더 만드는 거라면, exec()의 결과로는 호출한 프로세스의 PID가 새로 만들어진 프로세스에 적용되는거야

 

 

이렇게 만들어진 프로세스를 종료하려면 exit()명령을 사용하거나, 또 자식 프로세스는 부모 프로세스가 kill()과 abort()를 통해 죽일 수 있어, kill()은 자식만 죽고, abort()는 자식이 죽으면 부모도 같이 죽는 명령이야.

 

 

 

마지막으로 좀비 프로세스와 고아 프로세스가 있는데,

좀비 프로세스는 부모 프로세스가 wait()를 호출하기 전에 child 프로세스가 모든 동작을 수행하고 종료될때 발생하게 돼.

이때 운영체제는 child가 종료되었지만, 그 리소스를 회수하질 않고 child 프로세스에 대한 pid와 status를 남기고, 부모 프로세스가 wait()를 호출 시 OS가 수거해.

 

고아 프로세스는 반대로, 부모 프로세스가 wait()을 하지 않고 죽은 경우야. 이때 남겨진 프로세스를 고아 프로세스라 그래.

이 고아 프로세스를 처리하려고 OS는 각기 다른 방식을 채용하는데, 유닉스와 리눅스같은 경우, 고아 프로세스가 생기면 init()을 부모 프로세스로 설정해준뒤, init()에서 wait()함수를 주기적으로 호출하는 형태

 

 

그래서 이런것들 때문에, 우리가 프로세스를 구현할 때, 여러 프로세스의 정보를 핸들링할 수 있어야 해

그래서 필요한게 Process Control Block이야. (PBC, process descriptor, task control block)이라고도 불러

각각의 PCB는 하나의 프로세스에 대한 모든 정보를 가지고있어.

그래서 OS가 PCB를 보고 프로세스가 얼만큼 리소스를 사용하는지, 프로세스가 죽었을때 어떤 프로세스들을 수거해야하는지 알 수 있는거야.

 

 

음.. 좀 양이 많긴한데 정리하자면

기본적으로 프로세스는 실행 중인 프로그램의 인스턴스라고 할 수있고, PCB같은 구조체로 나타내

프로세스는 각기 독립된 영역을 가지고있고, (코드, 데이터, 힙, 스택)

프로세스는 다른 프로세스를 만들어서 트리처럼 계층 구조를 만들 수 있는데, 어떻게 종료가 되냐에 따라 좀비, 고아프로세스가 생겨.

 

기본적으로 프로세스를 만들려면 fork() and exec()를 사용하고

종료하려면 exit()을 사용하고, 이때 부모 프로세스는 wait()을 사용하여 자식 프로세스가 정상적으로 종료되었나 아닌가를 판단해

댓글