2024. 5. 1. 21:27ㆍCS/운영체제
프로세스 상태
하나의 프로세스는 여러 상태를 거치며 실행된다. 그리고 운영체제는 프로세스의 상태를 PCB를 통해 인식하고 관리한다.
프로세스가 가질 수 있는 대표적인 상태는 아래와 같다.
생성 상태
프로세스를 생성 중인 상태 즉, 이제 막 메모리에 적재되어 PCB를 할당받은 상태를 의미한다.
준비 상태
자신의 CPU 할당 차례가 올 때까지 기다리고 있는 상태이다. 준비 상태가 실행 상태로 전환되는 것을 디스패치라고 한다.
실행 상태
CPU를 할당받아 실행 중인 상태를 의미한다. 실행 상태인 프로세스는 할당된 일정 시간 동안만 CPU를 사용할 수 있다.
이때 할당된 시간을 모두 사용하여 타이머 인터럽트가 발생하면 다시 준비 상태로 돌아간다. 만약 실행 도중 입출력 장치를 사용하여 입출력 장치의 작업이 끝날 때까지 기다려야 한다면 대기 상태가 된다.
대기 상태
입출력 장치는 CPU 처리 속도에 비해 느리기 때문에 입출력 작업을 요청한 프로세스는 입출력 완료 인터럽트를 받을 때까지 대기해야한다. 입출력 작업이 완료되면 해당 프로세스는 다시 준비 상태로 CPU 할당을 기다린다.
종료 상태
프로세스가 종료된 상태이다. 프로세스가 종료되면 운영체제는 PCB와 프로세스가 사용한 메모리를 정리한다.
프로세스 계층 구조
많은 운영체제는 프로세스가 프로세스를 낳는 계층적인 구조로써 프로세스를 관리한다.
프로세스는 실행 도중 시스템 콜을 통해 다른 프로세스를 생성할 수 있다.
이때 프로세스를 생성하는 프로세스를 부모 프로세스, 부모 프로세스에 의해 생성된 프로세스를 자식 프로세스라고 한다.
부모 프로세스와 자식 프로세스는 다른 프로세스이기 때문에 다른 PID를 가지게 된다.
일부 운영체제에서는 자식 프로세스의 PCB에 부모 프로세스의 PID인 PPID(parent PID)가 기록되기도 한다.
프로세스 생성 기법
어떻게 부모 프로세스는 자식 프로세스를 생성하고 자식 프로세스는 자신만의 코드를 실행할 수 있을까?
부모 프로세스는 fork를 통해 자신의 복사본을 자식 프로세스로 생성해내고, 만들어진 복사본은 exec를 통해 자신의 메모리 공간을 다른 프로그램으로 교체한다.
fork와 exec는 시스템 콜이다. 부모 프로세스는 fork 시스템 콜을 통해 자신의 복사본을 자식 프로세스로 생성한다.
그림에서 보는 것처럼 자식 프로세스는 부모 프로세스의 복사본이기 때문에 부모 프로세스의 자원들이 상속된다.
하지만 PID나 저장된 메모리의 위치는 다르다.
fork를 통해 복사본이 만들어진 후, 자식 프로세스는 exec 시스템 콜을 통해 자신의 메모리 공간을 새로운 프로그램으로 덮어쓴다.
다시 말해 exec는 새로운 프로그램 내용으로 전환하여 실행하는 시스템 호출이다.
exec를 호출하면 코드 영역과 데이터 영역의 내용이 실행할 프로그램의 내용으로 바뀌고, 나머지 영역은 초기화된다.
실습
#include <stdio.h>
#include <unistd.h>
int main(){
printf("hello, os\n");
printf("my pid is %d", getpid());
return 0;
}
getpid를 사용하면 해당 프로세스의 PID를 알 수 있다. 실행할 때마다 PID값은 계속 바뀐다는 것을 알 수 있다.
#include <stdio.h>
#include <unistd.h>
int main(){
printf("parent pid is %d\n", getpid());
if(fork() == 0){
printf("child pid is %d\n", getpid());
}
return 0;
}
fork를 통해 자식 프로세스를 생성하는 코드이다. fork의 반환값이 0인 프로세스는 자식 프로세스이므로 getpid를 통해 자식 프로세스의 PID를 알 수 있다.
이 코드에서 중요한 것은 fork를 통해 복사본을 생성해 자식 프로세스를 만들었다는 것이다. 때문에 똑같은 작업을 수행하는 자식 프로세스가 생성되었다는 점이 중요하다.
#include <stdio.h>
#include <unistd.h>
int main(){
printf("parent pid is %d\n", getpid());
if(fork() == 0){
printf("child pid is %d\n", getpid());
}
printf("executed!\n");
return 0;
}
parent pid is 423409
executed!
child pid is 423410
executed!
이렇게 동일한 작업을 수행하는 프로세스를 생성할 수 있다.
#include <stdio.h>
#include <unistd.h>
void foo(){
printf("execute foo\n");
}
int main(){
if(fork() == 0){
printf("child pid is %d\n", getpid());
foo();
}
else{
printf("parent pid is %d\n", getpid());
foo();
}
return 0;
}
'CS > 운영체제' 카테고리의 다른 글
CPU 스케줄링 알고리즘 (2) | 2024.05.02 |
---|---|
CPU 스케줄링 개요 (0) | 2024.05.02 |
스레드 (0) | 2024.05.02 |
프로세스 개요 (0) | 2024.04.27 |
✨운영체제의 큰 그림 (0) | 2024.04.24 |