※ 전남대학교 박태준 교수님의 운영체제 강의를 듣고, 정리한 내용입니다.
프로세스 생성
프로세스가 생성되는 경우들을 먼저 살펴보면..
- 시스템 부팅과정에서 필요한 프로세스 생성
- 사용자 로그인 후 사용자와 대화 ( 제어 ) 를 위한 프로세스 생성
- bash, explorer.exe, finder.app등
- 새로운 프로세스를 생성하도록 하는 사용자의 명령
- 배치 작업 실행 시
- 사용자 응용프로그램이 시스템 호출로 새 프로세스 생성
여기서 중요한건, 메모리에 올라갔다고 해서 프로세스가 되는 건 아닙니다. PCB 가 존재하여 OS 가 제어 가능한 상태가 돼야, 프로세스라고 부를 수 있습니다. ( CPU 를 할당받아 실행 가능 형태 )
프로세스 생성 과정
- 생성하려는 실행파일의 경로를 OS 에 전달
- OS 는 메모리에 프로그램을 적재
- Code 영역에 프로그램의 코드 적재
- Data 영역에 전역 / 정적 변수들을 할당
- 스택, 힙은 아직 아무것도 없으니 초기화만 진행
- PCB 공간을 할당받고 ( malloc ) 필요한 정보를 채움
- 프로세스 식별자 결정 ( 새로운 PID 번호 할당 )
- 프로세스 정보 기록
- 프로세스 테이블에서 새 항목 할당
- 새로 할당된 프로세스 테이블에 PCB 연결
- PCB 에 프로세스 상태를 ready 상태로 표시하고, 준비 큐에 장착
복사에 의한 생성 : fork
프로세스를 처음부터 다시 만들면 시간이 되게 오래 걸립니다.
그래서 기존에 있던 프로세스를 복사하여 다른 프로세스를 만들도록 하여 시간을 줄였습니다.
( 프로세스를 복사하는 시스템 콜을 통해 프로세스 생성 )
( UNIX 계열의 경우 OS 는 시스템이 부팅할 때 0번 프로세스 ( init ) 만 자체적으로 생성하고, 나머지 프로세스는 복제를 통해 생성합니다. )
복사해서 다른 프로세스를 생성하는 과정의 장점은 다음과 같습니다.
- 자주 사용되는 프로세스에 대해 매번 반복할 필요가 없음
- 계층 구조를 따르니 관리하기가 편함
- Process간 통신
fork() 시스템 콜
fork 함수란, 실행 중인 프로세스로부터 새로운 프로세스를 복사하는 함수 입니다.
fork() 를 진행하고나면 실행 중인 프로세스와 똑같은 프로세스가 하나 더 만들어지고, fork 를 호출한 프로세스를 부모 프로세스, fork 된 프로세스를 자식 프로세스 라고 합니다.
자식 프로세스는 부모 프로세스의 모든 환경, 메모리 PCB 등을 복사하지만, 독립된 주소 공간에 위치하게 됩니다.
물론 PCB 에서 PID, PPID, CPID, 메모리 관련 정보 와 같은 내용은 달라지게 됩니다. ( 새로운 프로세스니 달라짐 )
- PID : 새로운 프로세스니 바뀜
- PPID ( Parent PID ) : 부모의 PID 로 바뀜
- CPID ( Child PID ) : 자식이 없으면 -1
- 메모리 관련 정보 : 독립된 주소 공간을 소유하니 바뀜
fork() 의 장단점
- 장점
- 프로세스의 생성 속도가 빠름
- 추가 작업 없이 자원 상속 가능
- 계층 구조를 따르니 시스템 관리를 효율적으로 할 수 있음
- 단점
- 매번 모든 Context 의 복사본을 만드는 것은 매우 비효율적
- 복사해서 쓰는 것이기 때문에, 맨 처음 만든 프로그램 프로세스 이외에는 다른 프로그램을 동작할 수 없음
- 이와같은 치명적인 단점이 있어서, 이를 보완하고자 UNIX OS 에서는 fork() 후 exec() 라는 시스템콜 호출
프로세스 오버레이 ( Process Overlay ) : exec() 시스템 콜
exec() 시스템콜은 기존의 프로세스를 새로운 프로세스로 전환 ( 재사용 ) 하는 함수입니다.
즉, 현재 실행중인 프로세스의 주소 공간에 새로운 응용프로그램을 적재하고 실행되게끔 해줍니다. ( 프로세스를 새로 생성하는 것이 아님 !! )
- fork() : 새로운 프로세스를 복사하는 시스템 호출
- exec() : 프로세스는 그대로 둔 채 내용만 바꾸는 시스템 호출
- 보통 fork() 를 통해 생성된 자식 프로세스가 exec() 실행
wait(), exit() 시스템 콜
wait() 시스템 콜 이란, 자식 프로세스가 끝나기를 기다렸다가 자식 프로세스가 종료되면 이어서 실행을 계속하는 시스템 콜 입니다.
그러면.. 자식이 언제 끝났는지를 알아야 하는데, 작업의 종료를 알리기 위한 시스템 콜인 exit() 시스템 콜 을 활용하여 ( 종료를 명시적으로 알림 ) 부모는 자식이 사용하던 자원을 더 빨리 회수할 수 있게 됩니다.
exit() 시스템 콜을 통한 프로세스 종료 과정
- 프로세스의 모든 자원 반환
- PCB 에 프로세스 상태를 Terminated 로 변경, PCB 에 종료 코드 저장
- 아직 PCB 가 프로세스 테이블에서 제거된 것은 아님.
- 부모가 종료를 확인해줘야 함
- 자식 프로세스들을 init 프로세스에게 입양
- 부모 프로세스에게 SIGCHLD 신호 전송 ( 일종의 종료 알림 신호 )
- 부모 프로세스는 SIGCHLD 신호 수신, wait() 시스템 콜 호출로 자식의 종료 코드 읽기 실행
- 죽은 자식이 남긴 정보를 확인
- 자식 프로세스의 PCB 제거
- 만약 이때 부모가 자식의 종료 신호를 제때 확인하지 못하면.. 자식은 좀비 프로세스 가 됨
이렇게 만드는 이유
- 프로세스 생성 과정 간소화
- 부모를 통해 자식 프로세스를 관리할 수 있으니 ( 계층 구조 ) 프로세스 관리가 쉬움
- 프로세스 간 통신 ( IPC )