4장 - 프로세스 관리

프로세스 생성

  • 부모 프로세스가 자식 프로세스 생성

  • 부모의 context를 복사함을 의미

    → 부모의 code, stack, data를 그대로 복사하여 생성 → cpu에서 instruction을 어디까지 수행하였는가(Program counter)

  • 프로세스의 트리(계층 구조) 형성

  • 프로세스는 자원을 필요로 함

    • 운영체제로부터 받음
    • 부모와 공유
  • 자원의 공유

    • 부모와 자식이 모든 자원을 공유하는 모델
      • 부모와 자식이 같은 메모리를 가지기 때문에 낭비가 됨
      • 효율성을 위해 PC(Program Counter)만 복사해 놓고 있다가 각자의 길을 갈 때(code, stack, data에서 변경이 일어 날 때) 복사함 → copy-on-write(COW) 기법
      • write가 발생하기 전까진 공유하겠다라는 생각
      • 하지만 원칙은 서로 다른 프로세스는 독립적으로 메모리 공간을 가져야 함
    • 일부를 공유하는 모델
    • 전혀 공유하지 않는 모델 → 일반적인 모델
  • 수행

    • 부모와 자식이 공존하며 수행되는 모델
    • 자식이 종료될 때까지 기다리는 모델
  • 주소 공간(Address Space)

    • 자식은 부모의 공간을 복사함(binary and OS data)
    • 자식은 그 공간에 새로운 프로그램을 올림
  • 유닉스의 예

    • fork()
      • 프로세스를 복제하는 과정
      • 부모를 그대로 복사(OS data except PID + binary)
      • 주소 공간 할당
    • exec()
      • 새로운 프로그램을 메모리에 올림
      • 자식을 생성하지 않고 exec() 을 하면 현재 프로세스가 새로운 프로그램이 될 수 도있음

    프로세스 생성은 보통 fork() + exec() 임

프로세스 종료

  • exit()
    • 프로세스가 마지막 명령을 수행한 후 운영체제에게 이를 알려 줌
    • 자식이 부모에게 output data를 보냄(via wait).
    • 프로세스의 각종 자원들이 운영체제에게 반납 됨
  • abort()
    • 부모 프로세스가 자식의 수행을 종료시킴
    • 자식이 할당 자원의 한계치를 넘어섬
    • 자식에게 할당된 task가 더 이상 필요하지 않음
    • 부모가 종료(exit)하는 경우
      • 운영체제는 부모 프로세스가 종료하는 경우 자식이 더 이상 수행되도록 두지 않음
      • 단계적 종료(맨 아래 자식 → 자식 → 자신순)

fork() 시스템 콜

int main(){
	int pid;
	pid = fork();
	if(pid == 0)
		printf("child");
	else if(pid > 0)
		printf("parent");
}
  • fork()를 실행한 이후 부터 분기가 되고 그 다음 시점 부터 실행이 됨
    • 그 이유는 부모의 context를 복제하기 때문에 같은 instruction을 보고 있음
  • 부모/자식을 구분은 fork() 의 return 값을 통해 구분
    • 부모 : 양수 값(자식의 pid값)
    • 자식 : 0

exec() 시스템 콜

  • replaces the memory image of the caller with a new program
int main(){
	int pid;
	pid = fork();
	if(pid == 0)
		execlp("/bin/data", "/bin/data", (char*) 0);
	else if(pid > 0)
		printf("parent");
}

int main(){
	printf("1");
	execlp("echo", "echo", "hello", "3", (char*) 0);
	printf("2");
}

//결과
1
hello 3

/* 참고 execlp()
int execlp( const char *file, const char *arg, ...);
1. 명령어 또는 실행할 파일 명
2. 프로그램 명령어 부터 parameter 전달
3. 마지막은 NULL로 전달

execlp("ls", "ls", "-al", NULL);
*/
  • exec()을 하고 끝나면 다시 돌아올 수 없음
  • exec()은 꼭 fork()를 하지 않고 실행해도 됨

wait() 시스템 콜

  • 커널은 child가 종료될 때까지 프로세스 A를 sleep 시킨다(block 상태)
  • Child process가 종료되면 커널은 프로세스 A를 깨운다(ready 상태)

https://user-images.githubusercontent.com/28971015/115235661-642e9a80-a155-11eb-83c6-88d9f053499b.png

exit() 시스템 콜

  • 자발적 종료

    • 마지막 statement 수행 후 exit() 시스템 콜을 통해 프로그램에 명시적으로 적어주지 않아도 main 함수가 return 되는 위치에 컴파일러가 넣어 줌
  • 비자발적 종료

    • 부모 프로세스가 자식 프로세스를 강제 종료시킴
      • 자식 프로세스가 한계치를 넘어서는 자원 요청
      • 자식에게 할당된 task가 더 이상 필요없을 경우
    • kill, break 등을 친 경우
    • 부모가 종료되는 경우
      • 부모 프로세스가 종료되기 전에 자식들이 먼저 종료
  • ? : frees all the resuorces, notify parent

  • ? : overlay new image

  • ? : sleep until child is done

  • ? : create a child(copy)

프로세스 간 협력

  • 독립적 프로세스(Independent Process)
  • 협력 프로세스(Cooperating Process)
  • 프로세스 간 협력 메커니즘(IPC : Inter-Process Communication)
    • Message Passing

      • 커널을 통해 메시지 전달
      • 프로세스 사이에 공유 변수(shared variable)를 일체 사용하지 않고 통신
      • Direct Communication : 통신하려는 프로세스의 이름을 명시적으로 표시
      • Indirect Communication : mailbox(or port)를 통해 메시지를 간접 전달

      https://user-images.githubusercontent.com/28971015/115238025-2c752200-a158-11eb-90d4-8bbb1b6938fc.png

    • Shared Memory

      • 서로 다른 프로세스 간에도 일부 주소 공간을 공유하게 하는 메커니즘
      • 시작할 때 kernel에 공유 영역에 대한 도움을 받지만 그 뒤부터는 둘이서 작업을 함

      https://user-images.githubusercontent.com/28971015/115238080-3b5bd480-a158-11eb-8198-63e3e2e6a30a.png

      ⭐thread는 사실상 하나의 프로세스이므로 IPC라고 보기는 어렵지만 동일한 process를 구성하는 thread들 간에는 주소 공간을 공유하므로 협력이 가능

    • PIPE

    • SOCKET

참고자료

반효경 교수님의 운영체제 강의를 참고하였습니다. (https://core.ewha.ac.kr/publicview/C0101020140318134023355997?vmode=f) https://ehpub.co.kr/tag/execlp/