본문 바로가기
운영체제

프로세스 생성

by LaTale 2020. 7. 12.

OS가 프로세스를 생성할 때 생성하는 행위(서브루틴) 자체의 명칭이 있다.

리눅스/유닉스에서는 fork()함수를, 윈도우에서는 CreateProcess()함수를 사용한다.

fork()함수에 대해 알아보도록 하겠다.


다음은 함수 원형이다.

1
2
3

#include<sys/types.h> #include<unistd.h> pid_t fork(void);

리턴 값은 새로 만들어진 프로세스의 PID이며, pid_t는 int라고 생각해도 된다.

자식 프로세스의 PC값조차도 부모 프로세스의 PC값과 똑같다.


간단한 예시들을 통해 fork의 작동 원리를 확인해보자.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

#include<sys/types.h> #include<unistd.h> int X = 0; main(){ int x = 0; pid_t pid = 0; x = 10; pid = fork(); if(pid == 0){ x += 10; X++; } else if (pid > 0){ x += 5; X += 2; } }

위와 같은 소스 코드가 있다.

위 소스 코드의 7번째 줄을 지난 시점에서의 메모리는 다음 그림과 같을 것이다.


앞서 보았던 프로세스의 구조를 그대로 보이고 있다. text부분에 Code 전체가 들어가고, 전역변수 X, 지역변수 x, 지역변수 pid가 들어간다.


8번째 줄인 fork()를 실행하면 다음 그림과 같이 변하게 된다.

fork()를 통해서 메모리에 있는 프로세스를 그대로 복사해 메모리의 다른 공간에 집어넣는다.

이후 부모 프로세스의 pid변수는 fork()의 리턴 값인 자식 프로세스의 pid로 바뀐다.

메모리 상엔 안보이지만 PC값 역시 복사되는데 여기서 PC값은 9번째 줄을 가리키고 있다.


자, 그럼 이제 프로세스는 2개가 되었다. 자식 프로세스와 부모 프로세스 중 어떤 것을 먼저 돌리든 결과는 일정하니 자세한 설명은 생략하고 넘어가겠다. pid 값이 다르니 서로 다른 if문이 실행된다 정도만 생각해보면 된다.


어쨌거나 위 소스 코드가 다 끝난 순간의 메모리는 다음 그림과 같다.

즉, 여기서 알 수 있던 점은 fork()를 통해 프로세스가 그대로 복사되며 부모와 자식 간의 PID를 다르게 줘 서로 다른 명령을 수행할 수 있다는 점과 순서는 무관하다는 점, 부모와 자식은 리소스를 공유하지 않는다는 점이 있다.



fork()를 통해서 프로세스가 그대로 복사된다고 했다. 그렇다면 동적 할당되는 변수는 어떻게 처리될까 ?? 라는 의문이 든다. 해당 변수에는 주소 값이 저장되기 때문에 복사되면서 어떻게 될지 의문이 생긴다.


다음과 같은 소스 코드가 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17

#include<sys/types.h> #include<unistd.h> int X = 0; main(){ int x = 0; int *y = NULL; pid_t pid = 0; x = 10; y = (int*)malloc(...); *y = 20; pid = fork(); if(pid == 0){ x += 10; X++; (*y) += 10; } else if (pid > 0){ x += 5; X += 2; (*y) += 20; } }

마찬가지로 fork() 직전인 9번째 줄에서의 메모리는 다음 그림과 같다.

y변수에는 주소 값이, 해당 주소 값(heap)에는 실제 값이 들어간다. fork()를 진행하면 다음 그림처럼 복사된다.

y변수의 주소 값과 힙에 저장된 값 모두 똑같이 복사함을 알 수 있다. 그렇다면 해당 값을 쓸 때 문제가 생기지 않을까 ?? 라는 생각이 당연히 든다.


뒷부분에서 다시 설명하겠지만 여기서도 한 번 보고 가자.


누구에 의해서, 언제 프로그램의 변수의 주소가 정해지는가 ?? 라는 질문에 대답은..

-> 컴파일러가 table을 보고 채운다. 이다.


그런데 여기서 컴파일러가 결정한 변수가 실제 변수의 주소와 같은가 ??둘 이상의 변수가 같은 주소를 가지는 경우(fork와 같이)는 어떻게 하는가 ?? 라는 의문이 생긴다.


해답은 다음과 같다.

1. 컴파일러는 변수들에게 임시로(가상의) 주소를 할당한다.

2. 서로 다른 프로그램의 변수는 같은 가상의 주소를 가질 수 있다.

3. 변수는 변수의 가상 주소와 다른 실제(물리) 주소에 위치할 수 있다.

4. 이런 것들은 OS가 책임진다.


조금 더 간단히 설명하자면 위 그림의 1024는 가상의 주소이기에 같아도 상관이 없다. 실제 물리적인 주소는 다른 곳에 위치하기 때문이다.



꽤나 복잡하다. 간단하게 정리해보자.

1. fork()를 통해 부모 프로세스를 복사한 자식 프로세스를 생성할 수 있다.

2. 부모와 자식은 리소스를 공유하지 않는다. 따라서 커뮤니케이션도 안된다. (소켓을 통해서 할 수 있다.)

3. 부모와 자식의 실행 순서는 상관없다. 하지만 자식 프로세스가 먼저 종료되어야만 한다. 따라서 부모 프로세스를 wait 시스템 콜을 통해 자식 프로세스가 종료될 때까지 기다리게 한다.

4. fork()를 여러 번 실행해 자식 프로세스를 여러 개 생성할 수 도 있다.

'운영체제' 카테고리의 다른 글

쓰레드(thread)  (1) 2020.08.05
프로세스  (0) 2020.07.11
시스템 콜  (0) 2020.07.07
OS Structure, Hardware Protection  (0) 2020.07.07
메모리  (0) 2020.07.06