열정 실천

프로세스 본문

CS/운영체제

프로세스

구운오니 2024. 9. 11. 16:07
프로세스  ::  실행 중인 프로그램

 

프로그램이 실행되어 메모리 상에 로드되면 그것을 프로세스라고 부른다. 

 

 

# 프로세스 vs 프로세서 

프로세서는 컴퓨터의 중앙 처리 장치인 CPU를 지칭하는 하드웨어이다. 

 

프로세스가 생성되는 4가지 단계 

 

1. 프로세스 제어 블록(PCB) 생성

2. 프로그램 메모리 할당 (메모리 세그먼트 참고)

3. 바이너리 프로그램 적재 (디스크->메모리)

4. 프로그램 초기화

 

메모리 세그먼트 

 

프로세스가 실행될 때 관련된 데이터가 관리되는 메모리상의 한 부분

  • Text 세그먼트 (코드 세그먼트)
  • Data 세그먼트
  • Heap 세그먼트
  • Stack 세그먼트

각각의 세그먼트에 저장되는 데이터 

 

 

 

*static 변수 : 프로그램이 실행되는 순간 data 세그먼트에 저장된다.

 

 

프로세스 상태 전이도

 

 

 

  • New (생성):
    • 프로세스가 생성 중인 상태. 아직 메모리에 올라오지 않았으며, 실행 대기 중이다.
  • Ready (준비):
    • 실행 가능한 상태로, CPU 할당을 기다리고 있다. 메모리에 로드되어 있으며, 실행 준비가 완료된 상태이다.
    • 스케쥴링 정책에 의해 CPU를 할당받으면 Running으로 상태가 바뀐다. 
  • Running (실행):
    • CPU에서 실행 중인 상태. 현재 CPU를 할당받아 프로세스가 실제로 실행되고 있다. 
    • I/O 이벤트가 생기면 Waiting으로 상태가 바뀐다. 
  • Waiting (대기):
    • 입출력 등의 작업을 기다리는 상태. CPU가 아닌 다른 자원을 기다리고 있어 실행되지 않고 잠시 멈춘 상태이다.
    • I/O가 작업을 끝내면 I/O Interrupt로 작업 완료를 알린다. I/O Interrupt가 발생하면 Ready로 이동한다. 
  • Terminated (종료):
    • 프로세스가 실행을 마친 상태. 더 이상 실행되지 않으며, 운영 체제에 의해 메모리 등 자원이 회수된다.

 

 

 

 

PCB 프로그램 카운터 블록

 

각 프로세스 마다 가지며 프로세스에 관한 모든 정보가 들어있다. 

 

하나의 프로세스가 중단되어 다른 프로세스에게 cpu를 내어주었다가 해당 프로세스가 다시 실행될 때 중단된 지점에서 재개할 수 있도록 PCB에 레지스터 값, 프로그램 카운터, 스택포인터, 프로세스 상태 등을 저장한다.

 

 

 

 

즉, CPU가 실행되는 프로세스가 변경될 때마다 각 프로세스가 가지고 있는 정보를 PCB에서 CPU로 저장하고 불러오는 과정을 거치는데 이를 문맥교환, Context Switch라고 한다. 

 

 

 

⚠ 문맥 교환이 잦으면 오버헤드가 발생한다. 

 

 

 

 

 

Unix에서 프로세스 생성해보기

 

프로세스 생성 System call

  • fork() : 새로운 프로세스 생성 
  • exec() : 새로운 메모리 공간 할당 

 

 

그림처럼 fork()의 경우 부모의 메모리를 복사하는 것이고 

exec()은 다른 프로그램을 수행하는 것! 

 

 

 

 

👉👉 프로세스를 생성한 뒤(frok)

자식 프로세스는 ls를 실행하고(exec)

부모 프로세스는 자식이 끝나기를 기다렸다가(wait)

출력을 하는 프로그램

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
        pid_t pid;

        /*fork a child process*/
        pid = fork();

        if(pid<0){ /*error occurred*/
                fprintf(stderr,"Fork Failed");
                return 1;
        }
        else if(pid==0){ /*child process*/
                execlp("/bin/ls","ls",NULL);
        }
        else{ /*parent process*/
                wait(NULL);
                printf("Child Complete");
        }
        return 0;
}

 

여기서 fork()가 반환하는 값에 따라서 부모 프로세스인지 자식 프로세스인지 구분할 수 있다. 

 

- 음수이면 에러 

- 0 이면 자식 프로세스

- 양수이면 부모 프로세스이다. (이 값은 자식 프로세스 번호를 뜻한다)

자식 프로세스의 ls 실행후 부모 프로세스의 출력이 실행된다.

 

* 캐스캐이딩 종료 : 부모 프로세스가 죽으면 모든 자식 그리고 그의 자식까지 모두 종료된다.