프로세스

yeolyeol·2024년 10월 30일
0

til

목록 보기
21/27
post-thumbnail

프로세스

컴퓨터에서 실행 중인 프로그램의 인스턴스. 메모리에서 실행 중인 프로그램 (Program in execution)

프로세스는 스택(Stack), 힙(Heap), 데이터(Data), 코드(Code)로 나뉜다. 

프로세스 문맥(Process Context)은 Process의 특정 시점의 상태를 표현하는 정보이다. 

먼저, 하드웨어 문맥(Hardware Context)으로는 프로그램 카운터(Program Counter), 각종 레지스터(Register)가 있다. 이들을 이용하여 해당 프로세스가 어디까지 실행되었는지를 알 수 있다. 
그리고, 프로세스의 주소 공간(Address space)도 문맥에 포함되며, 프로세스 관련 커널 자료구조인 PCB(Process Control Block), 프로세스 커널 스택(Process Kernel Stack)도 포함된다.

나는 프로그램의 인스턴스라는 문장을 봤을 때 바로 생각난 것은 Java의 객체 인스턴스화였다.

class Car {
	private name;
    private type;
    ...
}

class Solution {
	public static void main(String[] args) {
    	Car myCar = new Car("모닝", "경차");
    	...
    }
}

그럼, 프로세스는 위 코드에서 myCar와 같이 생각하면 될까?

프로그램 vs 클래스

프로그램은 실행 가능한 코드로 구성된 파일이다. 좀 쉽게 생각하면 파일 자체라고 생각하면 될 것 같다. 파일 그 자체로는 아무것도 할 수 없지만, 어떠한 일을 하거나 파일이 무엇인지 구현되어 있다.

클래스도 Car.java라는 클래스만 있다고 해서 무엇갈 할 수 있지 않다. new Car()와 같이 생성자로 인스턴스를 만들고 해당 인스턴스로 Car클래스에 구현된대로 동작한다.

프로세스 vs 객체 인스턴스

위에서 프로세스는 프로그램의 인스턴스라고 말했다시피 둘은 비슷한 성질을 나타낸다.
조금 더 풀어서 설명하자면, 특정 프로그램이 실행 중인 상태라고 할 수 있다.

우리가 객체를 생성할 때, 즉 인스턴스를 생성할 때 구현한 클래스의 속성(상태)와 메서드(행위)를 갖게 된다. 마찬가지로, 프로세스는 프로그램의 코드와 현재 상태, 자원 사용 정보 등을 포함한다.

즉, 프로그램 - 프로세스클래스 - 객체 인스턴스는 서로 비슷한 구조를 띈다!

구성 요소

Java를 빗대어 표현한 것은 여기까지 하고,
이제 프로세스를 구성하는 것에 대해 알아보자.

PCB(Process Control Block)

프로세서 제어 블록이라고도 하며, 각 프로제스는 하나의 PCB를 갖는다. 프로세스는 운영체제에서 PCB에 의해 표현되는데, PCB는 해당 프로세스에 대한 모든 정보를 저장하고 있다.
리눅스에서는 task_struct라는 이름으로 PCB를 구현하고 있다.

프로세스의 모든 정보
프로세스의 상태(생성, 준비, 실행, 대기, 종료), Program Counter, Registers, MMU info, CPU 사용시간, Process ID(PID) 등


1. 운영체제가 관리상 사용하는 정보
- Process state 
- Process ID
- Scheduling information : 프로세스의 중요도, 스케줄링 큐 포인터 등 스케줄링 파라미터 정보
- Priority : 프로세스의 우선순위

2. CPU 수행 관련 하드웨어 값
- Program counter : 해당 프로세스가 이어서 실행해야 할 명령의 주소를 가리키는 포인터
- Register : 프로세스가 인터럽트 이후 올바르게 작업을 이어가기 위해 참조하는 CPU 레지스터 값

3. 메모리 관련
- Code, Data, Stack의 위치 정보, base/limit 레지스터 값

4. 파일 관련
- open file descriptors : 열린 파일 목록

프로세스의 상태

  • 생성(new)
    이제 막 생성된 상태, OS의 커널에 PCB 등이 생성됨.
  • 준비(ready)
    CPU의 서비스를 받기 위해 Ready Queue에서 대기 중인 상태
  • 실행(running)
    CPU에 의해 실행되고 있는 상태
  • 대기(waiting)
    I/O나 다른 event를 기다리며 멈춰있는 상태
  • 종료(terminated)
    실행을 완료하는 등의 이유로 종료된 상태

이러한 상태들이 하나의 라이프사이클처럼 동작하는데, 그림과 함께 보자.

그림으로 봐도 이해가 될 수 있겠지만, 심심해서 Java로 동작을 비슷하게 구현해 보았다.

코드

ProcessState

프로세스의 상태를 나타내는 enum 클래스다.

public enum ProcessState {
    NEW, READY, RUNNING, WAITING, TERMINATED
}

MyProcess

MyProcess라는 나만의 프로세스 클래스를 만들었다. 각 상태별 수행하는 코드가 들어있다.

public class MyProcess {
    private String name;
    private ProcessState state;

    public MyProcess(String name) {
        this.name = name;
        this.state = ProcessState.NEW; // 초기 상태는 NEW
        System.out.println(name + " is now NEW.");
    }

    public void ready() {
        if (state == ProcessState.NEW) {
            state = ProcessState.READY;
            System.out.println(name + " is now READY.");
        }
    }

    public void run() {
        if (state == ProcessState.READY) {
            state = ProcessState.RUNNING;
            System.out.println(name + " is now RUNNING.");
            // 실행 중인 상태에서 대기하거나 종료할 수 있는 로직 추가 가능
            simulateDownload();
        }
    }

    public void waitFor() {
        if (state == ProcessState.RUNNING) {
            state = ProcessState.WAITING;
            System.out.println(name + " is now WAITING.");
            retryDownload();
        }
    }

    public void terminate() {
        if (state == ProcessState.RUNNING || state == ProcessState.WAITING) {
            state = ProcessState.TERMINATED;
            System.out.println(name + " has been TERMINATED.");
        }
    }

    public ProcessState getState() {
        return state;
    }
    
    private void simulateDownload() {
        // 다운로드 도중에 오류가 발생할 수 있음
        try {
            // 다운로드 진행 중
            System.out.println(name + " is downloading...");
            Thread.sleep(2000); // 2초 대기
            // 네트워크 오류 시뮬레이션
            boolean networkError = true; // true로 설정하여 오류 발생 시뮬레이션
            if (networkError) {
                waitFor(); // 오류 발생 시 대기 상태로 전이
            } else {
                terminate(); // 오류 없이 완료 시 종료 상태로 전이
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    private void retryDownload() {
        System.out.println("Retrying download...");
        try {
            Thread.sleep(2000); // 재시도 대기
            // 재시도 성공적으로 다운로드 완료 시뮬레이션
            terminate(); // 종료 상태로 전이
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Main

위에서 짠 코드를 실행하는 클래스다.

public class Main {
    public static void main(String[] args) {
        MyProcess downloadProcess = new MyProcess("File Download Process"); // NEW

        // 상태 전이
        downloadProcess.ready();    // NEW -> READY
        downloadProcess.run();      // READY -> RUNNING
        // 상태 전이가 자동으로 이루어짐
    }
}

결과

시나리오

내가 짠 코드의 전체적인 시나리오를 읊어보자면, 다운로드 과정에 대한 가상의 시나리오를 표현해 보았다.

0. NEW : 새로운 프로세스를 생성한다.
1. NEW READY : 프로세스가 생성되어 준비 상태로 전이된다.
2. READY RUNNING : 다운로드 프로세스가 실행 중이다.
3. RUNNING WAITING : 다운로드 중 네트워크 오류가 발생하여 대기 상태로 전이된다.
4. WAITING TERMINATED : 사용자 요청 후 재시도가 성공적으로 완료되어 종료 상태로 전이된다.

출력문

File Download Process is now NEW.
File Download Process is now READY.
File Download Process is now RUNNING.
File Download Process is downloading...
File Download Process encountered a network error and is now WAITING.
Retrying download...
File Download Process has been TERMINATED.
profile
한 걸음씩 꾸준히

0개의 댓글

관련 채용 정보