운영체제 5-2강 (프로세스와 관련한 시스템 콜)

늘보·2021년 7월 6일
0

OS

목록 보기
9/25

→ Open in Slid

  • 본 글은 이전에 사용하던 영상 강의 필기 앱인 'Slid'에서 필기 했던 내용을 Velog로 옮긴 내용입니다.
  • 본 글은 이화여대 반효경 교수님 2017학년도 1학기 운영체제 강의를 기반으로 작성되었습니다.
  • 강의 링크 : http://www.kocw.net/home/search/kemView.do?kemId=1226304

* 이 자료는 https://higunnew.tistory.com/25?category=873234 이 블로그에서 정리한 내용을 토대로 제가 강의 내용을 복습하며 중요한 부분을 강조하기 위해 만든 자료입니다. 이후부터는 운영체제 12강으로 이어집니다.

프로세스 복제, 프로세스 생성에 대해 다시 한번 상기해보자. 프로세스 복제는 프로세스의 문맥(Context)을 모두 복사하는 것이다. 부모 프로세스의 주소 공간 code, data, stack 영역을 그대로 복사하며 프로세스의 CPU 문맥 (Program Counter)를 복사하는 작업을 하는 것이다. 이렇게 일단 프로세스가 만들어지면, 부모 프로세스와 자식 프로세스는 서로 독립적인 프로세스가 되기 때문에 자원을 공유하려고 하지 않는 것이 원칙이다.

 그러나 지난 번에도 언급했듯이 프로세스 문맥을 복사하는 것은 큰 overhead가 발생한다. 게다가 프로세스를 말 그대로 '복사'하는 것인데 똑같은 내용이 메모리에 또 올라간다면 너무나 큰 낭비가 아니겠는가? 따라서 리눅스와 같은 운영체제들은 부모 프로세스와 자식 프로세스가 겹치는 부분의 자원을 최대한 공유하려고 한다. 그러다가 각자의 길을 가게 되는 때에 도달해서야 복사를 실행한다. 이것을 Copy-On-Write(COW) 기법이라고 한다. 즉, Write가 발생했을 때 Copy를 한다는 뜻이다. 이 사실을 꼭 인지하고 강의를 진행하도록 하자!

프로세스와 관련한 시스템 콜 대표적인 4가지

프로세스와 관련한 시스템 콜은 대표적으로 네 가지가 있다.

  • fork()
  • exec()
  • wait()
  • exit()

fork() system call

fork()는 프로세스를 생성하는 system call이다. 다음 예시를 통해 이에 대해 알아보자.

운영체제 5-2강 (프로세스와 관련한 시스템 콜) image

Linux 환경에서 fork()를 하는 간단한 C 프로그램이다. pid = fork(); 라는 부분에서 자식 프로세스가 생성된다. 이를 쉽게 생각한다면 위 코드가 그대로 하나 복사되는 것이다. 물론 main()의 처음부터 다시 실행되는 것은 아니다. 왜냐하면 프로세스의 복사가 일어나면 부모 프로세스의 '문맥'을 복사하면서 CPU의 문맥인 Program Counter도 복사가 된다고 했다. 이때 PC는 pid = fork();라는 코드 영역을 가리키고 있었으므로 그다음 코드 부분을 실행하게 되는 것이다.

 그런데 fork의 문제점을 찾자니 너무나 극명하다. 첫 번째는 나랑 똑같이 생긴 프로세스를 하나 복제해 놨으니, 복제된 프로세스가 복제된 것인지 원본인지 구별할 방법이 없는 것이다. 두 번째로는 fork를 했으니 프로세스의 제어 흐름이 부모의 것과 자식의 것이 동일할 것이라고 생각할 수 있는 것이다. 이러한 문제들을 해결하기 위해 fork() 시스템 콜은 리턴 값을 달리한다. 다음 linux의 fork함수 매뉴얼(man)을 참고하자. http://man7.org/linux/man-pages/man2/fork.2.html

귀찮을까봐 친절히 캡처도 했다.(감사합니다..) 자식 프로세스일 경우 0을 리턴하고 부모 프로세스인 경우는 자식 프로세스의 Process id가 반환한다. 이를 통해서 복제됐지만 서로 다른 프로세스들의 제어 흐름을, 서로 다르게 설정할 수 있게 되는 것이다.

운영체제 5-2강 (프로세스와 관련한 시스템 콜) image

exec() system call

어떤 프로세스를 완전히 새로운 프로세스로 태어나도록 하는 것이 exec이다. 지난 강에서 잠깐 언급했던 내용이다. 자식 프로세스는 어찌 되었든 부모 프로세스의 모든 것을 복사한 것이기 때문에 복사된 직후에는 비슷한, 혹은 완전히 같은 흐름을 갖게 될 수밖에 없다. 이때 exec를 통해 다른 프로그램을 실행하게 되면 완전히 부모 프로세스와 같은 제어 흐름에서 벗어나게 되며, 아예 새로운 프로세스로 탈바꿈하게 된다. 다음의 예를 살펴보자.

운영체제 5-2강 (프로세스와 관련한 시스템 콜) image

 중간에 execlp("/bin/date", "/bin/date", (char*)0); 부분을 살펴보자. child 프로세스는 해당 블록을 실행하게 될 텐데 이 함수를 호출하게 되면 bin폴더에 있는 date라는 프로그램을 실행하며 기존의 프로그램이 a.out이었다면 a.out이 아닌 date 프로그램을 실행하게 되어 전혀 다른 프로세스로 변신한다. 따라서 원래 프로세스인 a.out의 프로세스로 다시 돌아올 수는 없게 된다. 물론 fork를 하고 나서만 exec를 할 수 있는 것은 아니다.

 다음의 예시를 살펴보자.

운영체제 5-2강 (프로세스와 관련한 시스템 콜) image

만약 이 프로그램을 실행하게 된다면 execlp("bin/date", "/bin/date", (char*)0); 이 실행되며 해당 프로그램 a.out에서 date로 완전히 탈바꿈하게 되고 다시 돌아오지 않기 때문에 가장 아래 줄에 있는 printf("\n Hello, I am parent!\n");는 실행되지 않게 된다.

0개의 댓글