티스토리 뷰

Study/Linux

[Study] Linux에서의 Process 와 Thread

생각많은 소심남 2013. 4. 5. 13:59

이전에 올린 포스트 중에 Process와 Thread, Task의 차이에 대해서 간략하게 정리해본 것이 있었다.

2013/02/15 - [About School] - [Study] Task / Thread

그 포스트에서 잠깐 언급하기로는 Process와 Thread의 구분이 되어 있는 운영체제가 있는가 하면 동일한 개념으로 사용하는 운영체제가 있다 했었다. 사실 그 게 어떤건지에 대해서 궁금해 했었는데 OLC에 공개되어 있는 고건 교수님의 Kernel Of Linux 라는 강좌에서 이에 대한 이야기를 잠깐 다루고 있어서 소개하고자 한다.


 리눅스에서 Process라는 것은 실행할 수 있는 프로그램으로 설명할 수 있다. 실행이 가능하다는 것이지 현재 실행중(RUNNING)일 수도 있고, 실행이 끝난 상태(WAIT or ZOMBIE)일 수도 있고, 혹은 실행하려고 대기중인 상태(READY)일 수 있다. 그런데 뭐든지 생성되기 위해서는 그 것의 시작과 끝이 있다시피 process도 생성되기 위해서는 process를 생성하는 주체와 그걸로 나오는 결과물이 존재할 것이다. Kernel이라고 하는 기본 프로그램 상에 shell이라 불리는 parent process가 상주해 있고, 이 shell이 fork()라는 system call을 부르면 parent와 완전히 똑같은 child process가 생성되어 ready queue에서 대기하게 된다. 이 때 동작중인 parent process가 wait()를 호출하게 되면 child process가 실행되는 것이 전체적인 process 처리 과정이다. 

 그런데 다들 알다시피 process는 cpu에서 처리되는 것이고, 그러면 parent process가 처리할 때의 CPU 상태랑 child process가 처리될 때의 CPU의 상태는 달라야 하는게 이치에 맞을 것이다. 만약 process 마다 쓰는 CPU의 데이터가 같다면 굳이 child process와 parent process로 나눠놓을 의미가 없어지는 것이다. 그래서 process는 각자가 cpu에 의해서 처리될 때 자기 자신의 정보와 그 cpu의 state vector를 Kernel에 저장하게 되는데 이걸 Process Control Block (PCB) 라고 하고 위와 같이 프로세스가 전환되는 과정에서 PCB가 바뀌는 일련의 과정을 Context Switch라고 한다.


예를 들어 user가 ls라는 function을 부르는 순간에는 CPU가 shell이라는 프로그램을 parent process로 처리한다. 그런데 cpu는 process 하나만 할당 받아서 처리하기 때문에 따로 ls를 처리하기 위한 child process를 생성하게 된다. 그래서 대기하고 있다가 parent가 wait을 부르는 순간 앞에서 언급한 PCB를 주고 받는 Context Switch가 발생한다. 그러면 parent process는 child process가 exit()을 호출해서 완료될 때까지는 계속 대기하고 있을 것이고, 그게 끝나는 순간 다시 sh를 실행시키게 될 것이다. 이때 child process는 자신이 가지고 있는 PCB 정보만을 남기고 나머지는 모두 terminate 시키는 이른바 zombie state에 이르게 된다. 

 결국 위에서 한말을 되짚어 보면 Process라는 건 어떻게 보면 scheduling을 할 수 있는 기본 단위라고도 표현할 수 있다. 그런데 이 글의 제목은 Thread에 관해서 설명하는 내용을 담을 거 같았는데 지금까지 계속 process의 처리 과정에 대해서만 설명하고 있다. 그건 바로 process와 thread의 차이가 바로 PCB의 구성요소에 있는 것을 설명하고자 하기 위해서다.

 앞에서도 언급했다시피 fork()를 하게 되면 Parent와 완전히 똑같은 child Process가 생성된다고 했었다. PCB도 마찬가지다. Parent와 완전히 똑같은 Child PCB가 생성되는 것이다. 다만 이게 child process가 execute될때만 쓰여질 뿐 process가 처리되면서 parent PCB와는 내용이 달라지게 될 것이다. 그러면 이 PCB에는 어떤 내용들이 담겨 있을까? 리눅스 운영체제를 사용하고 있다면 이걸 직접 확인해볼 수 있다.

이 header를 열어보면 약 2000줄 이상의 코드가 나오게 되는데 이중에 task_struct라는 struct를 살펴보자



무척 많다. 앞에서 말한 것처럼 Process는 scheduling 할 수 있는 기본 단위, 즉 task라고 할 수 있고 이 Process가 수행될때 필요한 정보를 모두 PCB라고 해서 Kernel에 저장한다. 그러면 PCB에는 Process ID나 Process의 Priority, status 앞에서 이야기했던 CPU의 state vector도 들어가 있을 것이다. 이런 task의 기본적인 정보도 담고 있겠지만 task가 수행되면서 다른 task와 정보를 교환할 때 필요한 자료형도 들어 있을 것이다. 

 그런데 그럼 다시 원래대로 돌아가서 parent process가 fork()를 호출하면 앞에서 말했다시피 parent process를 그대로 복사한 child process가 생성되고 이때 PCB도 같이 생성될 것이다. 그런데 이부분을 잘 살펴보면 뭔가 이상할 수 있다. 사람이 쓰는 컴퓨터인 이상 한번에 하나의 process만 돌리지는 않을것이다. 분명 인터넷도 하고 문서작업도 하고... 언급되지는 않지만 background에서 실행되고 있는 수많은 daemon process도 존재한다. 물론 부팅할 때 이 모든 process가 생성되는 게 아니기에 처음부터 shell에서 fork를 사용해서 생성이 될 것이다. 그런데 이렇게 복사하는 과정을 매 process fork시마다 계속 복사하는 것이다. 말 그대로 heavy weight copy가 발생하고 있는 것이다. 분명 이로 인한 성능 저하가 발생할 것이다. 

 그런데 바로 위의 task_struct를 살펴보면 몇몇 struct 들은 pointer 형식으로 선언되어 있는 것을 확인할 수 있다. 즉 이에 대한 정보는 Memory로부터 읽어온다는 뜻인데, 다르게 말하면 이 정보들을 다른 process와 공유하기 위해서 이런 pointer 형식으로 작성했을 것이다. 그러면 task들을 구분하는 기본정보들만 process가 처리할 수 있게 하고 이런 pointer 형식은 원래의 parent와 공유해서 쓰면 어떨까? 그러면 앞에서 발생했던 heavy weight copy가 아닌 light weight copy, 그러니까 기본정보들만 선택해서 child가 쓰게끔 하는 것이다. 이렇게 하면 copy에 따른 overhead도 발생하지 않을 것이다. 이런 접근 방식이 Thread 인것이다.얼핏 보면 process와 동일한 구조이긴 하지만 필요한 기본 정보만 선별해서 갖고 있는 process이기 때문에 다른 말로 Light-Weight Process 라고도 할 수 있을 것이다.

간단한 예가 아래와 같은 것이다.


이전 방식대로 Process를 만들면 같은 struct를 사용함에도 heavy weight copy가 발생했었지만 Thread를 사용하면 굳이 새로 복사본을 만들지 않더라도 기본정보만으로 Task를 처리할 수 있게 된다. 

물론 Process를 새로 생성하는 fork()와는 다른 Clone()이란 system call을 사용하면 위와 같이 Thread를 생성해서 task를 처리할 수 있다. 그래서 Clone의 인자로 flag를 설정해서 해당 기능에 대한 copy 권한을 부여하는 식으로 동작한다. 궁금한 사람은 터미널에서 man clone이라고 치면 clone에 관한 설명이 나올 것이다.

이게 Linux에서 Thread와 Process의 차이이다. 


Reference :

Wikipedia : Process Control Block (http://en.wikipedia.org/wiki/Process_control_block)

OLC 고건 교수님 강좌  : Kernel of Linux (http://olccenter.or.kr)

Havard CS Lecture note : http://www.eecs.harvard.edu/~mdw/course/cs161/notes/processes.pdf 


댓글