gunnew의 잡설

5-2강. 프로세스와 관련한 시스템 콜 본문

Operating System

5-2강. 프로세스와 관련한 시스템 콜

higunnew 2020. 1. 24. 00:30
반응형

  프로세스 복제, 프로세스 생성에 대해 다시 한번 상기해보자. 프로세스 복제는 프로세스의 문맥(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이다. 다음 예시를 통해 이에 대해 알아보자.

 

fork() 시스템 콜

 

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

 

fork() 를 한 결과 프로세스가 하나 생성되며 위 사진처럼 두 코드가 실행되는 것

 

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

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


exec() system call

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

 

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

 

 다음의 예시를 살펴보자.  

 

 

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


wait() system call

 wait 시스템 콜은 해당 프로세스를 잠들게 한다. 그런데 그냥 잠들게 하는 것이 아니라 자식 프로세스가 종료될 때까지 기다리게 하는 것이다. 즉, 부모 프로세스를 blocked state로 보내는 것이다. 물론 자식 프로세스가 종료되면 다시 ready state로 돌아오게 된다. 앞서 프로세스가 수행될 때 부모 프로세스와 자식 프로세스가 공존하며 수행되는 모델, 즉, 서로 CPU를 얻기 위해 경쟁하는 모델 하나와 자식 프로세스가 종료될 때까지 부모 프로세스가 기다리는 모델 하나가 있다고 했다. wait system call은 프로세스로 하여금 후자 모델을 따르게 하는 호출이다.

 

 가령 우리가 작성한 프로그램(뭐든 상관없다. 아무 프로그램)을 리눅스 쉘 환경에서 실행한다고 가정하자. 우선 쉘 커맨드인 CLI도 하나의 프로세스라는 것을 인지하자. 이 CLI 환경에서 ./a.out이라는 명령어를 통해 내가 만든 프로그램을 실행한다면 해당 프로그램(a.out)이 종료될 동안 CLI에서는 아무것도 할 수 없다. 결국 CLI가 a.out이라는 프로그램의 프로세스를 자식 프로세스로서 생성하게 되며 이 자식 프로세스가 끝날 때까지 기다리게(wait) 되는 것이다.

 


exit() system call

 exit는 말 그대로 시스템 콜이 호출되는 순간 거기서 프로세스가 종료된다. exit도 마찬가지로 지난 번에 언급했지만, 자발적 종료가 있고 비자발적 종료가 있다. 자발적 종료란 프로세스의 마지막 statement에 도달하면 자동으로 종료되는 것을 말한다. 하지만 여기서 주의해야 할 점이 있다. 다음 프로그램의 예시를 살펴보자. 

 

 

프로그램 중간에 exit()이 호출되었다. 이것은 자발적 종료일까 비자발적 종료일까? 자발적 종료이다. 자발적 종료란 프로그램이 본래 수행하려던 statement를 수행하고 종료가 되는 것을 말한다. 위 예시에서는 프로그램, 그러니까 프로세스 자신이 직접 exit()를 호출했기 때문에 자발적 종료이다.

 

 반면 비자발적 종료는 프로세스가 진행되는 와중에 바깥에서 갑자기 프로세스를 종료하는 것을 말한다. 첫 번째로 자식 프로세스가 자원의 한계치를 넘어서 요구하는 경우 혹은 자식에게 시킬 일이 다 끝났을 경우 부모 프로세스가 강제 종료하는 경우가 있다. 두 번째로는 사용자가 키보드로 ctrl + c와 같은 커맨드를 입력하거나 kill, break와 같은 커맨드를 입력하는 경우가 있다. 세 번째로는 부모 프로세스가 종료되는 경우이다. 프로세스의 세계에서는 부모 프로세스보다 자식 프로세스가 먼저 종료가 되어야 한다고 했다. 따라서 부모 프로세스가 종료해야 한다면 자식 프로세스의 흐름에 관계없이 강제적으로 자식 프로세스를 종료하게 된다. 

 

본 글들은 이화여대 반효경 교수님 2014학년도 1학기 운영체제 강의를 기반으로 작성됩니다.

링크 : http://www.kocw.net/home/search/kemView.do?kemId=1046323

반응형

'Operating System' 카테고리의 다른 글

6-1강. CPU 스케줄링  (0) 2020.01.24
5-3강. 프로세스 간의 협력  (0) 2020.01.24
5-1강. 프로세스 관리(Process Management)  (0) 2020.01.23
4강. 스레드(Thread)  (0) 2020.01.22
3-2강. 프로세스(Cont'd)  (0) 2020.01.21
Comments