프로세스(3)

프로세스 생성과 복사

프로세스 생성

프로세스는 언제 생성되는가?
1. 시스템 부팅과정
2. 사용자의 로그인 후 사용자와 대화를 위한 프로세스 생성
3. 새로운 프로세스릉 생성하도록 하는 사용자의 명령
4. 배치작업 실행 시
5. 사용자 응용프로그램이 시스템 호출로 새 프로세스 생성

단, 메모리에 올라갔다고 무조건 프로세스가 아님

  • 그냥 메모리에 올라와만 있으면 아무런 의미가 없음

  • PCB가 존재하여 OS가 제어 가능한 형태가 되어야함. - cpu를 할당 받아 실행가능.

    프로세스 생성 과정

  1. 생성하려는 파일의 경로를 OS에 전달
  2. OS는 메모리에 프로그램을 적재
  • 코드영역은 코드를 적재, 데이터영역에 정적/전역 변수를 할당.
  • 스택과 힙은 초기화만 시킴
  1. PCB공간을 할당받고 필요한 정보를 채움
  • PID 번호 할당.... 프로세스 정보 기록... 할당된 프로세스테이블에 PCB 연결...
    4.PCB에 프로세스 상태를 ready 상태로 표시 후 큐에 장착.

    너무 할일이 많다! 그래서 복사에 의한 생성 테크닉

기존에 있는 프로세스가 다른 프로세스를 생성!

  • 프로세스를 복사하는 시스템 콜을 통해서 프로세스 생성

  • 리눅스 : frok() 시스템콜, Windows : CreateProcess() 시스템콜(Win32Api)

    Unix 계열의 OS는 시스템이 부팅할 때 0번 프로세스(init)만 자체적으로 생성
    -> 나머지는 복제를 통해 생성함

  • 자주 사용되는 프로세스에 대해 매번 반복할 필요가 없음.ex)bash shell

  • 관리상 편리해짐

  • 프로세스간 통신

fork() 시스템 콜

기존에 프로세스를 새로운 프로세스로 복사하는 함수
실행 중인 프로세스와 똑같은 프로세스가 하나 더 만들어짐! int pid = fork();

  • fork를 호출한 프로세스 : 부모 프로세스, fork된 프로세스: 자식 프로세스
  • 부모 프로세스의 모든 환경,메모리,PCB 등을 복사
  • 부모와 동일한 모양이지만, 독립된 주소 공간에 위치

단 PCB에서 아래 내용은 달라짐!

  • PID...PPID...CPID...메모리관련 정보(독립된 주소공간을 소유하므로)...

fork() 실행과정

자식은 부모의 Program Counter도 복제하여, fork() 다음의 if(pid==0) 라인부터 실행됨.

  • 자식 프로세스는 pid=fork(); 이전 라인을 실행하지 못함.

fork()함수의 리턴값

  • 부모 프로세스에게는 자식 프로세스의 pid 리턴
  • 자식 프로세스에게는 0 리턴
 1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/wait.h>
 4 #include <unistd.h>
 5
 6 int main() {
 7 pid_t pid;
 8 int i, sum=0;
 9
 10 pid = fork(); // fork! -> create a child process
 11 if(pid > 0) { // Run by the parent
 12 printf("Parent: fork()'s return == Child pid = %d\n", pid);
 13 printf("Parent: pid = %d\n", getpid());
 14
 15 wait(NULL); // Wait for the child
 16 printf("Parent has been finished\n");
 17 return 0;
 18 }
 19 else if(pid == 0) { // Run by the child
 20 printf("\t-Child: fork()'s return pid = %d\n", pid);
 21 printf("\t-Child: pid = %d, parent's pid = %d\n", getpid(), getppid());
 22
 23 for (i=1; i<=100; i++) sum += i;
 24
 25 printf("\t-Child: sum = %d\n", sum);
 26 return 0;
 27 }
 28 else { // Error
 29 printf("fork error");
 30 return 0;
 31 }
 32 }

fork()의 장점과 단점

장점
  • 프로세스의 생성 속도가 빠름
  • 추가 작업 없이 자원을 상속할 수 있음
  • 시스템 관리를 효율적으로 할 수 있음
단점
  • 매번 모든 Context의 복사본을 만드는것은 매우 비효율적
  • 특히, 맨 처음 만든 프로세스 이외에는 다른 프로그램을 동작 할 수 없음.
  • Unix OS는 fork()를 한 다음 exec() 라는 시스템 콜을 호출함.

프로세스 오버레이 : exec() 시스템콜

기존의 프로세스를 새로운 프로세스로 재사용하는 함수

  • 현재 실행중인 프로세스의 주소공간에 새로운 응용프로그램을 적재하고 실행
  • fork() : 새로운 프로세스를 복사하는 시스템 호출
  • exec() : 프로세스는 그대로 둔 채 내용만 바꾸는 시스템 호출

!! 프로세스를 새로 생성하는게 아님 !!

  • 프로세스의 Pid 변경 없음
  • 프로세스의 메모리 공간에 새로운 프로그램이 적재
  • 보통 fork()를 통해 생성된 자식 프로세스가 exec() 실행
  • 로더가 exec()를 통해 호출됨

exec() 실행과정

메모리
  • code 영역의 기존의 내용을 지우고 새로운 코드로 바꿔버림.
  • data 영역이 새로운 변수로 채워지고 힙/스택 영역이 리셋.
PCB
  • pid,ppid,cpid, 메모리 관련은 유지 -> 새로운 프로세스가 전환되더라도 부모로 돌아올수 있음
  • program counter 및 기타 register, 파일 정보 등이 모두 리셋

자식이 일하는동안 부모는..? wait() 시스템콜

자식 프로세스가 끝나기를 기다렸다가, 자식 프로세스가 종료되면 이어서 실행을 계속하는 시스템콜

그럼 자식이 끝난걸 어케 아는가? exit() 시스템콜

작업의 종료를 알리는 시스템콜(종료를 명시적으로 알림으로 자식의 사용자원을 빨리 회수!)

종료코드
  • 부모 프로세스에게 상태나 종료의 이유를 전달하는 값 ex) exit(1)

  • 보통 정상종료는 0, 나머지는 1-255 범위 내에서 임의로 사용

  • main() 함수의 리턴 값 return 0; == exit(0);

  • 이걸 부모가 확인해야지 최종적으로 자식 프로세스가 종료됨.

    종료과정

    1.프로세스의 모든 자원 반환 : 코드,데이터,스텍,힙 등 모든 메모리 자원을 반환.
    2.PCB에 프로세스 상태를 Terimnated로 변경, PCB에 종료코드 저장.
    3.자식 프로세스들을 init 프로세스에게 입양
    4.부모 프로세스에게 SIGCHLD (종료알림) 신호 전송

    부모의 의무 : SIGCHLD를 수신하고, wait() 시스템 호출로 자식의 종료코드 읽기 실행 후 죽은 자식이 남긴 정보를 확인 후 , 자식 프로세스의 PCB가 완전히 제거됨.
    만약에 부모가 자식의 종료신호를 제때 확인하지 못하면 자식은 좀비 프로세스가 됨!
    PCB가 남아있기 때문! 즉 좀비프로세스는 PCB 제거가 안되고 남은 자식프로세스!

    정리해서 UNIX OS 에서의 프로세스 생성 과정

fork() -> exec()의 구조

  • fork()를 통해서 프로세스를 만들고, exec()를 통해 필요한 프로세스를 실행함.

  • 이때 생성을 한 프로세스는 부모 프로세스. 생성된 프로세스는 자식 프로세스.

  • 부모는 wait()을 통해 기다리고, 자식은 exit()를 통해 자신의 종료를 알림.

    모든 프로세스의 최초의 조상 : INIT

    왜이렇게 하는가...

    생성과정의 간소화
    관리가 쉬워짐
    프로세스간 통신

  • 원래 프로세스는 독자적인 메모리공간을 가진것으로 운영됨.

  • 서로 간섭이 불가, 통신도 불가 : 서로 통신이 필요하다면 -> SIGCHLD

  • 파일을 이용해 서로 의사소통 : fork()가 사용됨.

    int fd; //파일 시스템변수
    foo(){
    	fd = open("pile") //파일을 연다
      if(fork() == 0) {
      	read(fd,...); //하나의 파일로 서로 의사소통
      }
      else{
      	write(fd,...)'//하나의 파일로 서로 의사소통
      }

좋은 웹페이지 즐겨찾기