시스템 소프트웨어

프로세스 (Process)

masimelo 2023. 2. 5. 19:06

프로세스

  • 프로세스
    • 컴퓨터에서 연속적으로 실행되고 있는 컴퓨터 프로그램
    • 프로그램을 구동하여 프로그램 자체와 프로그램의 상태가 메모리 상에서 실행되는 작업의 단위
    • 메모리에 적재된 프로그램의 명령어를 CPU가 실행함으로써 동작됨
    • 한 프로세스는 하나의 프로그램 수행에 대응됨
      • 하나의 프로그램을 여러번 구동하면, 여러 개의 프로세스가 실행됨
  • 프로그램
    • 컴퓨터에서 실행될때 특정 작업을 수행하는 일련의 명령어들의 모음을 말함
    • 하드 디스크 등에 저장되어 있는 실행 코드

프로세스의 상태

  • 커널 내에는 준비 큐, 대기 큐, 실행 큐 등의 자료구조가 있으며, 커널은 이것을 이용하여 프로세스의 상태를 관리함
  • 프로세스의 상태
    • 생성(create)
      • 프로세스가 생성되는 상태
    • 준비(Ready)
      • 프로세스가 CPU를 사용하고 있지는 않지만, 언제든지 사용할 수 있는 상태
    • 대기(Waiting)
      • 프로세스가 입출력 완료, 시그널 수신 등 어떤 사건을 기다리고 있는 상태
      • 보류(block)라고 부르기도 함
    • 완료(Terminated)
      • 프로세스의 실행이 종료된 상태

시분할

  • 시분할
    • 각 프로세스에 CPU의 시간 자원을 할당하고, 교대로 반복 실행하는 것
  • 시간 슬라이스
    • 프로세스가 선점 다중 작업 시스템에서 실행할 수 있는 시간대
    • 퀀텀이라고도 함
  • 병렬처리로 작동하는 것과 같은 착각을 주지만, 실제로는 작은 시간 슬라이스에 의해 전환되며 처리됨
    • 프로세서가 여러 사용자의 프로그램을 처리하지만, 사용자는 자신의 프로그램만을 처리하는 것처럼 느낌

컨텍스트 스위치

  • 컨텍스트 스위치
    • CPU가 기존의 프로세스에서 다음 프로세스를 수행하도록 새로운 프로세스의 상태 또는 레지스터를 교체하는 작업
  • 프로세스 컨텍스트
    • 컨텍스트 스위치로 인해 실행이 중단된 이후, 스케쥴러에 의해 다시 실행될 때 필요한 프로세스와 그에 대한 정보
    • 컨텍스트에는 다음정보가 포함됨
      • 프로세스 상태
      • 프로그램 카운터
      • 레지스터
      • 프로세스 번호
    • 컨텍스트는 프로세스의 PCB에 저장됨

프로세스 함수

프로세스 번호

  • 프로세스 번호 PID
    • UNIX 계열의 운영체제는 각 프로세스에 부여하는 음이 아닌 정수
    • 각 프로세스는 고유한 프로세스번호를 가지고 있음
    • 실제로는 특수한 프로세스를 위하여 0과 1은 부여되지 않음
      • 0번 프로세스 : 스와퍼 프로세스
      • 1번 프로세스 : 초기화 프로세스
  • 프로세스가 종료되면 해당 프로세스 번호는 재사용이 가능함

getpid() 함수

#include <unistd.h>

pid_t getpid(void);
  • 설명
    • 현재 프로세스의 PID를 반환
  • 인자
    • 없음
  • 반환
    • 현재 프로세스의 PID
    • 오류가 발생하는 경우 없음

getppid() 함수

#include <unistd.h>

pid_t getppid(void);
  • 설명
    • 현재 프로세스의 부모 프로세스의 PID를 반환
  • 인자
    • 없음
  • 반환
    • 부모 프로세스의 PID
    • 오류가 발생하는 경우 없음

exit() 함수

#include <stdlib.h>

void exit(int status);
  • 설명
    • 현재 프로세스를 정상적으로 종료함
    • status & 0377 값을 부모 프로세스에 전달함
  • 인자
    • status : 프로세스의 종료 상태 (0과 255 사이의 정수)
  • 반환
    • 없음

fork() 함수

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

pid_t fork(void)
  • 설명
    • 현재 프로세스와 거의 동일한 자식 프로세스를 생성함
    • 현재 프로세스의 메모리 이미지를 새로운 메모리 영역에 복사함으로써, 자식 프로세스는 부모프로세스의 메모리 공간 복사본을 가짐
  • 인자
    • 없음
  • 반환
    • 성공
      • 부모 프로세스에게 자식 프로세스의 PID
      • 자식 프로세스에게 0
    • 오류시 -1

wait() 함수

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

pid_t wait(int * status);
  • 설명
    • 자식 프로세스가 종료할 때까지 대기함
    • 부모 프로세스가 자식 프로세스 보다 먼저 종료되는 것을 방지하기 위함
  • 인자
    • status : 자식 프로세스의 종료상태를 저장할 메모리 공간에 대한 포인터
      • 종료 상태에 따라 다른 값이 저장됨
          상위 1바이트 (8비트) 최하위 1바이트(8비트)
        정상 종료된 경우 프로세스 종료 상태  
        비정상 종료된 경우   프로세스를 종료한 시그널 번호
      • 비트 연산을 통해 프로세스 종료 상태 또는 반환값을 확인할 수 있음
        • 미래에 시스템 또는 컴파일러가 변경될 경우, 비트 연산은 문제가 될 수 있음
    • 따라서, 프로세스 종료 상태를 확인하는 매크로를 제공함
  • 반환
    • 성공 시 종료한 자식 프로세스의 PID
    • 오류시 -1

상위 1바이트(8비트)

waitpid() 함수

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

pid_t waitpid(pid_t pid, int * status, int options);
  • 설명
    • 특정 자식 프로세스가 종료할 때까지 기다림
  • 인자
    • pid : 자식 프로세스의 PID
    • status : 자식 프로세스의 종료상태를 저장할 때 메모리 공간에 대한 포인터
    • options : 함수의 동작을 제어하는 옵션
      • sys/wait.h 헤더파일에 정의된 다음의 플래그를 OR비트 연산자와 함께 사용할 수 있음
        • WNOHANG : 자식 프로세스가 종료되지 않더라도, 즉시 반환
        • WUNTRACED : 멈추거나 상태가 보고되지 않은 자식들을 위해 반환
      • 위의 제어가 필요하지 않은 경우에는 0을 사용
  • 반환
    • 성공 시 종료한 자식의 프로세스 PID
    • 오류시 -1

wait()과 waitpid() 함수 예시

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

int main(int argc, char const *argv[]) {
    int val = 10;
    pid_t pid = 0;
    int status = 0;

    printf("Hello My PID is %d\n", getpid());

    pid = fork();
    if (pid == -1) {
        perror("fork() error");
        exit(-1);
    } else if (pid == 0) {
        printf("I'm a child. My PID is %d\n", getpid());
        printf("I'm child. My parent PID is %d\n", getppid());

        val += 1;
    } else {
        printf("I'm parent. My child PID is %d\n", pid);
        wait(&status);
        printf("I'm parent. My child PID is exited\n");
    }
    printf("My PID is %d, val is %d\n", getpid(), val);
    return 0;
}

프로세스 종료 상태 매크로

  • 프로세스 종료 상태를 확인하는 매크로

프로세스 종료 상태 매크로 예시

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

int main(int argc, char const *argv[]) {
    pid_t pid = 0;
    int status = 0;

    printf("Hello My PID is %d\n", getpid());

    pid = fork();
    if (pid == -1) {
        perror("fork() error");
        exit(-1);
    } else if (pid == 0) {
        printf("I'm a child. My PID is %d\n", getpid());
        exit(1);
    } else {
        wait(&status);
        **if ((status == 0) || (status > 255))**
            printf("child PID is exited with %d\n", **status >> 8**);
        else {
            printf("child PID is exited with %d\n", status);
        }
    }
    return 0;
}

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

int main(int argc, char const *argv[]) {
    pid_t pid = 0;
    int status = 0;

    printf("Hello My PID is %d\n", getpid());

    pid = fork();
    if (pid == -1) {
        perror("fork() error");
        exit(-1);
    } else if (pid == 0) {
        printf("I'm a child. My PID is %d\n", getpid());
        exit(1);
    } else {
        wait(&status);
        **if (WIFEXITED(status))**
            printf("child PID is exited with %d\n", **WEXITSTATUS(status)**);
        else {
            printf("child PID is exited with %d\n", status);
        }
    }
    return 0;
}

프로그램 실행 함수

execl() 함수

#include <unisd.h>

int execl(const char * path, const char * arg, ...);
  • 설명
    • 현재 프로세스의 이미지를 새로운 프로세스 이미지로 덮어씀
    • 실행 가능한 파일을 실행함
  • 인자
    • path : 실행 가능한 파일의 경로
    • arg, … : 실행할 파일의 명령형 인자(가변 인자)
      • 마지막 인자는 항상 NULL
  • 반환
    • 오류시 -1

execl() 함수 예시

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

int main(int argc, char const *argv[]) {
    pid_t pid = 0;
    int status = 0;

    pid = fork();
    switch (pid) {
    case -1:
        perror("fork() error");
        exit(-1);
    case 0:
        execl("/bin/ls", "ls", "-a", "-l", NULL);
        break;
    }
    if (pid > 0) {
        wait(&status);
    }
    return 0;
}

execv() 함수

#include <unistd.h>

int execv(const char * path, char const *argv[]);
  • 설명
    • 현재 프로세스의 이미지를 새로운 프로세스 이미지로 덮어씀
    • 실행 가능한 파일을 실행함
  • 인자
    • path : 실행 가능한 파일의 경로
    • argv : 실행할 파일의 명령행 인자를 저장할 배열
      • 배열의 마지막 요소는 항상 NULL
  • 반환
    • 오류시 -1

execv() 함수 예시

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

int main(int argc, char const *argv[]) {
    pid_t pid = 0;
    int status = 0;
    char *args[] = {"ls", "-a", "-l", NULL};

    pid = fork();
    switch (pid) {
    case -1:
        perror("fork() error");
        exit(-1);
    case 0:
        execv("/bin/ls", args);
        break;
    }
    if (pid > 0) {
        wait(&status);
    }
    return 0;
}

execve() 함수

#include <unistd.h>

int execve(const char * path, char const * argv[], char const * envp[]);
  • 설명
    • 현재 프로세스의 이미지를 새로운 프로세스 이미지로 덮어씀
    • 실행 가능한 파일을 실행함
  • 인자
    • path : 실행 가능한 파일의 경로
    • argv : 실행할 파일의 명령행 인자를 저장할 배열
      • 배열의 마지막 요소는 항상 NULL
    • envp : 환경변수를 저장할 배열
      • 배열의 마지막 요소는 항상 NULL
  • 반환
    • 오류시 -1

execve() 함수 예시

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

int main(int argc, char const *argv[]) {
    pid_t pid = 0;
    int status = 0;
    char *args[] = {"ls", "-a", "-l", NULL};
    char *envp[] = {"USER=sohee", "HOME=/home/sohee/", NULL};

    pid = fork();
    switch (pid) {
    case -1:
        perror("fork() error");
        exit(-1);
    case 0:
        execve("/bin/ls", args, envp);
        break;
    }
    if (pid > 0) {
        wait(&status);
    }
    return 0;
}

execvp() 함수

#include <unistd.h>

int execvp(const char * name, char const * argv[]);
  • 설명
    • 현재 프로세스의 이미지를 새로운 프로세스 이미지로 덮어씀
    • 환경 변수에 등록된 실행가능한 파일을 실행함
  • 인자
    • name : 실행 가능한 파일의 이름
    • argv : 실행할 파일의 명령행 인자를 저장할 배열
  • 반환
    • 오류시 -1

execvp() 함수 예시

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

int main(int argc, char const *argv[]) {
    pid_t pid = 0;
    int status = 0;
    char *args[] = {"ls", "-a", "-l", NULL};

    pid = fork();
    switch (pid) {
    case -1:
        perror("fork() error");
        exit(-1);
    case 0:
        execvp("ls", args);
        break;
    }
    if (pid > 0) {
        wait(&status);
    }
    return 0;
}