목차
개요
상위의 포스팅에서는 스케줄링 큐를 통하여 여러 종류의 스케줄러들이 프로세스의 생성 할당 종료 등을 관할하는지에 대해서 알아보았다.
따라서 이번 시간에는 운영체제가 프로세스를 어떻게 생성하는지 프로세스간의 관계 등을 알아보자.
프로세스 생성 Process Creation
프로세스는 또 다른 프로세스를 생성할 수 있는데 생성하는 프로세스를 부모 프로세스라고 하고 생성된 프로세스를 자식 프로세스 라고 한다. 결과적으로는 아래와 같은 프로세스의 트리를 형성한다.
식별자
가장 최상부에는 init 라는 프로세서가 pid 값을 1을 가지고 있는 것을 확인 할 수 있는데 pid는 프로세스 식별자 로서 정수 자료형을 가지고 있고 각 프로세스의 고유값을 할당 해주기 위해서 모든 프로세스가 가지고 있는 값이다.
* 최근에는 pid=1 인 init 라는 프로세스가 systemd 라는 더 많은 서비스를 제공해주는 첫번째 프로세스로 변경되었다.
자원 할당
상위 포스팅에서 말했듯이 각 프로세스 들은 명령을 수행하는 데 필요한 자원 등이 필요한데 이는 스케줄러가 할당을 해주거나 부모 프로세스의 자원 일부분을 할당받아서 사용할 수 있다. 후자 같은 방법은 추후에 자식프로세스에 할당되는 메모리가 과다하게 발생하여 시스템을 과부하 상태로 만드는 현상을 방지 할 수 있다.
데이터 전달
또한 부모 프로세스는 자식 프로세스에게 자원 뿐만 아니라 데이터도 전달 해줄 수 있다.
1. 자식 프로세스는 부모 프로세스의 복사본이다.
2. 자식 프로세스가 자신에 적재될 새로운 프로그램을 가지고 있다.
실행
부모 프로세스와 파생된 자식 프로세스가 실행 되는 경우는 총 두가지가 있는데
1. 부모와 자식이 병행하게 실행이 된다.
2. 부모는 자식의 실행이 모두 종료될때까지 기다린다.
fork(), exec(), wait()
UNIX 운영체제 내에서 프로세스 생성 실행 등에 대한 시스템콜의 종류들이다.
fork() 시스템 콜
프로세스가 새롭게 생성된다. 이때 새로운 프로세스를 위한 메모리 할당과 복사 등이 이루어진다. 자식 프로세스를 생성할때는 0을 0 이상인 경우에는 부모 프로세스를 생성한다.
이후에 각 프로세스에는 getpid()를 이용해 고유 프로세스 ID를 할당하여준다.
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, const char * argv[]) {
int pid;
puts("Press Ctrl-C to stop");
pid = fork();
if (pid == -1) {
// possible errors: EAGAIN, ENOMEM.
perror("Failed to fork");
return -1;
}
if (pid == 0) {
// 자식 프로세스의 경우
execlp("\bin\ls","ls", NULL),
} else {
// 부모 프로세스의 경우
wait(NULL)
printf("Child Complete")
}
return 0;
}
exec() 시스템 콜
자식 프로세스가 만들어질 때 execlp(exec 의 시스템 콜에, l [list; 리스트 형식으로 나열하는 인자], p [path ;경로가 정해진 인자]) 을 이용하여 자신의 메모리 공간을 새로운 프로그램으로 교체를 하게된다. 기존의 프로그램을 내리고 새 프로그램이 덮여 씌워 진다고 생각하자
wait() 시스템 콜
부모 프로세스의 경우에 이 시스템 콜울 이용하여 자식이 종료 상태를 확인 할 수 있고 그에 따라서 종료된 자식프로세스에 있던 자원 등을 반납을 하게 만들 수있다. 자식이 종료될 때를 기다리는 경우 이 시스템 콜로 인해서 부모 프로세스의 실행이 재개가 된다.
프로세스 종료 Process Terminate , exit()
프로세스가 종료될 때 exit() 시스템 콜을 통하여 운영체제에게 프로세스 삭제를 요청한다.
물리 메모리 가상메모리 파일 입출력 버퍼등 프로세스의 모든자원이 할당 해지되어 운영체제로 반납된다.
부모 프로세스가 자식 프로세스를 종료 시키는 경우
- 자식이 자신에게 할당된 자원을 초과 사용할 때
- 자식에게 할당된 기능이 더 이상 필요없을 때
- 부모가 exit() 를 하는데 자식이 이후에도 실행을 하는 것을 허용하지 않을때
몇몇 시스템에서는 부모프로세스가 종료된 상태에서도 자식 프로세스가 존재할 수 없는경우가 있는데 이러한 환경에서는 부모 프로세스가 종료되면 따라서 자식 프로세스도 종료 되게 만든다. 이를 연쇄식 종료(cascading termination)라고 한다
비정상적인 프로세스
좀비 프로세스 : 종료되었지만 부모의 wait() 시스템 콜의 부재로 자원 반납이 되지 않는 프로세스
wait() 시스템 콜 설명에서 보다 싶이 부모가 wait() 콜로 종료 상태를 받아서 자식 프로세스의 자원과 정보 등을 회수 후에 운영체제가 이를 삭제 해야하는데 이 정보들이 메모리에 남아 있어 문제가 발생한다. 정보들의 크기가 큰 편이 아니라서 큰 성능 저하는 있지 않지만 PID 특성상 한정된 양의 할당 가능한 PID 중에서 좀비 프로세스의 것들이 사용 불가능 하게 되므로 wait() 호출로 상태 회수가 필요하다.
고아 프로세스 : 부모프로세스가 wait() 를 호출 하는 대신에 종료하는 경우에 그 하위에 있던 자식 프로세스
즉 부모 프로세스가 자식 프로세스보다 먼저 종료를 하는 경우인데 이러한 경우에는 프로세스가 자원을 낭비할 수도 있고 시스템이 프로세스가 종료하기 전까지 큐 등으로 관리를 해야되므로 성능저하의 원인이 될 수 있다. 따라서 UNIX시스템의 경우에 가장 상위의 부모 프로세스인 init() [지금은 systemd()]에서 주기적으로 wait()를 통하여 남아있는 고아프로세스를 색출하여 좀비 프로세스가 되는 것을 방지한다. 이런식으로 init()에서 관리를 해주기는 해도 성능저하 방지를 위해 각 부모 프로세스 들이 wait()를 빠짐없이 해주는 것이 좋다.
'CS > Operating System' 카테고리의 다른 글
프로세스 :: 공유 메모리 시스템 at POSIX (0) | 2022.08.31 |
---|---|
프로세스 :: 프로세스 간 통신(IPC) 개념, 종류 (0) | 2022.08.29 |
프로세스 :: CPU 스케줄링 종류 (0) | 2022.08.18 |
프로세스 :: 문맥 교환과 오버헤드 (0) | 2022.08.17 |
프로세스 :: 스케줄링 큐와 스와핑 (0) | 2022.08.16 |