• 07. 프로세스의 연산

    2021. 9. 20.

    by. ahntree

    728x90

    1. 프로세스의 구조

    프로세스는 4가지 영역으로 구성된다.

     

     

    코드 영역 (code area)

    프로그램의 본문이 기술된 곳으로 텍스트 영역(text area)이라고도 한다. 프로그래머가 작성한 프로그램은 코드 영역에 탑재되며 읽기 전용이다. 자기 자신을 수정하는 프로그램은 존재하지 않기 때문이다.

     

     

    데이터 영역 (data area)

    코드가 실행되면서 사용하는 변수나 파일 등의 각종 데이터를 저장하는 곳이다. 상수(constant)의 경우에는 읽기 전용이지만 다른 변수는 읽기와 쓰기가 모두 가능하다.

     

     

    스택 영역 (stack area)

    운영체제가 프로그램을 실행하기 위해 부수적으로 필요한 데이터를 모아놓은 곳이다. 예를 들어 프로세스 내에서 함수를 호출하면 함수를 수행하고 돌아올 원래 위치를 스택에 저장한다. 운영체제가 주체이기 때문에 사용자에게는 보이지 않는 영역이다.

     

     

    힙 영역 (heap area)

    코드에서 동적으로 만들어지는 데이터가 저장된다. C의 malloc, Node나 JVM의 힙메모리 등으로 사용된다.

     

     

     

    2. 프로세스의 생성과 복사

    사용자가 프로그램을 실행하면 운영체제는 프로그램을 메모리로 가져와 코드 영역에 넣고 프로세스 제어 블록을 생성한다. 메모리에 나머지 영역을 확보한 후 프로세스를 실행한다.

     

    하지만 언제나 프로세스가 새로 생성되는 것은 아니다. 이미 실행한 프로세스를 단순히 복사하는 것으로 새로운 프로세스를 제공할 수 있다.

     

     

    fork() 시스템 호출의 개념

    fork() 시스템 호출실행 중인 프로세스로부터 새로운 프로세스를 복사하는 함수이다. 크롬의 새 창을 연다고 해서 크롬을 다시 새로 실행하진 않는다. 대신 이미 실행 중인 크롬 프로세스를 복사하여 새로운 프로세스를 만들어 낸다.

     

    이 때, 이미 실행 중인 프로세스를 부모 프로세스, 복사된 프로세스를 자식 프로세스라고 한다. 두 프로세스는 부모-자식 관계로 연결된다.

     

     

    fork() 시스템 호출의 동작 과정

    fork() 시스템 호출을 하면 대부분의 영역이 복사되지만 그렇지 않은 부분들이 있다.

     

    • 프로세스 구분자(PID)
    • 메모리 관련 정보 (메모리의 위치가 바뀌므로)
    • 부모 프로세스 구분자(PPID)와 자식 프로세스 구분자(CPID)

     

     

    fork() 시스템 호출의 장점

    프로세스를 새로 만들지 않고 복사하는 것에는 다음과 같은 장점들이 있다.

     

    1. 프로세스의 생성 속도가 빠르다

    하드 디스크에서 가져오지 않고 메모리에서 바로 복사하기 때문이다.

     

    2. 추가 작업 없이 자원을 상속할 수 있다

    부모 프로세스가 사용하던 자원을 추가 작업 없이 자식 프로세스에 상속할 수 있다.

     

    3. 시스템 관리를 효율적으로 할 수 있다

    부모-자식 간에 구분자로 연결되어 있기 때문에 자식 프로세스를 종료할 때 자식 프로세스가 사용하던 자원을 부모 프로세스가 정리할 수 있다.

     

     

    fork() 시스템 호출의 예

     

    #include <stdio.h>
    #include <unistd.h>
    void main() {
    int pid;
    pid = fork();
    if (pid < 0) {
    printf("Error");
    exit(-1);
    }
    else if (pid == 0) {
    printf("Child");
    exit(0);
    }
    else {
    printf("Parent");
    exit(0);
    }
    }

     

    위 코드가 실행되어 fork()문을 만나면 똑같은 내용의 자식 프로세스를 생성한다. 이 때 fork()문은 부모 프로세스에는 0보다 큰 값을, 자식 프로세스에는 0을 반환한다.

     

    기억해야 할 것은 fork()문 이전에 연 파일이나 선언한 변수는 모두 자식 프로세스에 상속된다는 것이다.

     

     

     

    3. 프로세스의 전환

    같은 프로그램 기반이라고 해도 안의 내용물이 다른 프로세스를 실행해야 할 경우가 있다. 이럴 땐 먼저 fork()로 프로세스를 복사하고 exec() 시스템 호출을 사용하면 된다.

     

     

    exec() 시스템 호출의 개념

    기존의 프로세스를 새로운 프로세스로 전환하는 함수이다. 프로세스는 그대로 둔 채 내용만 바꾼다. 이미 만들어진 프로세스 구조체에 새로운 코드 영역만 가져오면 되기 때문에 운영체제의 작업이 수월해진다.

     

     

    exec() 시스템 호출의 동작 과정

    각종 프로세스 구분자(PID, PPID, CPID)만 남겨두고 프로세스의 나머지 내용을 새로운 것으로 바꾼다. 코드 영역은 새로운 코드로, 데이터 영역은 새로운 데이터로, 스택 영역은 리셋된다.

     

     

    exec() 시스템 호출의 예

     

    #include <stdio.h>
    #include <unistd.h>
    void main() {
    int pid;
    pid = fork();
    if (pid < 0) {
    printf("Error");
    exit(-1);
    }
    else if (pid == 0) {
    execlp("mplayer", "mplayer", NULL);
    exit(0);
    }
    else {
    wait(NULL);
    printf("mplayer Terminated");
    exit(0);
    }
    }

     

    부모 프로세스는 fork()문을 통해 자식 프로세스를 생성하고 wait()문을 통해 자식 프로세스가 끝날 때까지 기다린다. 자식 프로세스는 execlp()문을 통해 mplayer 프로세스를 실행하고 실행이 끝나면 부모 프로세스의 wait()문으로 돌아온다.

     

    exec()문을 실행하더라도 구분자가 동일하게 남아있기 때문에 돌아올 수 있는 것이다.

     

     

     

    4. 프로세스의 계층 구조

    유닉스의 프로세스 계층 구조

    유닉스에서 커널이 처음 메모리에 올라와 부팅이 되면 커널 관련 프로세스를 여러 개 만든다. 그 중에서 init 프로세스가 전체 프로세스의 출발점이 된다.

     

    운영체제는 프로세스를 효율적으로 관리하기 위해 init 프로세스를 만든 다음 나머지 프로세스를 자식 프로세스로 설정한다. 즉, 트리 구조를 이룬다.

     

     

    프로세스 계층 구조의 장점

    1. 여러 작업의 동시 처리

    여러 작업을 동시에 처리할 때 fork()문을 이용해서 프로세스를 바로바로 복사하면 동시에 처리하기가 용이하다.

     

    또한 서로 다른 작업을 동시에 처리할 때도 용이한데, A라는 작업을 하다가 B라는 작업도 해야 할 경우 A를 복사하고 exec()문을 실행해 B로 프로세스의 내용을 바꾼다. 효율적으로 자원을 관리할 수 있고 기존의 부모-자식 관계도 유지할 수 있다.

     

    2. 용이한 자원 회수

    자식 프로세스가 사용하던 자원을 부모 프로세스가 회수하기 때문에 운영체제가 모든 자원 관리를 맡지 않아도 되서 편리하다.

     

     

    고아 프로세스

    부모 프로세스가 자식 프로세스보다 먼저 죽는 경우 자식 프로세스의 자원을 회수할 프로세스가 남아있지 않게 된다. 이렇게 프로세스가 종료된 후에도 비정상적으로 남아 있는 프로세스를 고아 프로세스 혹은 좀비 프로세스라고 한다.

    728x90

    '운영체제' 카테고리의 다른 글

    댓글