[시스템 프로그래밍] 프로세스 (2)
fork() 함수가 실행되는 순간 프로세스가 복사된다.
if(fork() == 0) 문장을 실행할 때 fork() 프로세스가 복사되고 복사되자마자 자식은 죽는다.
부모는 리턴값이 0이 아니기에 무한 루프에 빠진다.
어셈블리 부분을 살펴보자.
원래대로라면 부모는 무한 루프에 빠져 입력받을 수 없는 상태겠지만, 명령어 실행 시 &를 붙이면 백그라운드에서 실행하게 돼 명령어를 입력받을 수 있다.
ps 명령어로 현재 돌아가는 프로세스를 확인했을 때 자식과 부모 모두 돌아가고 있음을 확인할 수 있다 (부모가 죽지 않아서 자식이 좀비 상태이다)
이후 kill 명령어로 부모를 죽이면 부모와 자식 모두 정리됨을 확인할 수 있다.
부모가 죽지 않으면서 자식이 정리되지 않는 경우가 문제가 되는데.. 이 경우 wait 함수를 사용해서 처리한다.
int wait(int *child_status) : 자식 프로세스의 종료와 동기할 때 사용한다.
현재 프로세스를 자신의 자식 프로세스 중 하나가 종료 될 때 까지 정지시킨다.
함수가 종료 될 때는 종료한 자식 프로세스의 pid가 리턴된다.
예시를 통해 살펴보자.
fork() == 0 부분에서 프로세스가 복제된다.
부모는 wait 함수에 걸려서 fork에서 복제된 자식에 동기된다.
자식은 exit 함수에 걸려 제거된다.
자식이 제거됐으니 부모는 제거된 자식을 정리해 좀비 프로세스가 되는걸 방지하고, wait 상태에서 깨어나 자신도 exit 함수를 만난다.
핵심은 wait 함수로 제거된 자식의 좀비 상태를 제거하는 부분이다.
waitpid(pid, &status, option) : pid 값을 설정해 특정 프로세스 아이디를 기다릴 수 있고, option 값을 설정해 기다리는 프로세스의 상태를 설정할 수 있다.
기존 wait 함수는 종료된 자식이 여러 개일 때 순서에 상관 없이 제거했지만, waitpid 함수는 제거할 프로세스를 설정할 수 있다. (pid값을 -1으로 설정 시 wait와 동일하게 동작한다)
unsigned int sleep(unsigned int secs) : 자신을 secs 동안 정지시킨다. 정상적으로 깨어나면 0 리턴, 그 외에는 잔여시간 리턴
int pause(void) : 호출하는 프로세스를 특정 signal을 받기 전 까지 정지시킨다.
int execve(char * filename, char* argv[], char *envp[]) : filename을 현재 프로세스의 환경변수를 이용해 code / data / stack 정보를 덮어쓴다.
argv envp 는 null 문자로 끝나는 포인터 배열이다. command line의 argument와 환경 변수를 의미한다.
에러가 없다면 한 번 호출되고 리턴되지 않는다.
리턴되지 않으면 myargv[0] 의 정보를 현재 프로세스 정보에 덮어쓴다.
execve는 fork와 함께 사용되는 경우가 많다.
fork로 프로세스를 복제한 후, execve로 프로세스가 다른 작업을 수행할 수 있도록 한다.
처음에 컴퓨터를 키면 0번 프로세스가 만들어진다.
0번 프로세스에서 fork와 exec을 수행해 1번 프로세스인 init 프로세스가 만들어지고, 1번 프로세스가 여러 가지 서버 프로세스를 만든 후 로그인 shell을 올린다.
사용자는 올라간 shell을 사용해 작업을 수행한다.
shell은 명령어를 읽고 여러 자손들을 만들어낸다.
shell은 사용자의 명령을 처리 해 주는 응용 프로그램이다.
사용자의 입력을 키보드로부터 받아들이고, eval 함수로 명령어를 해석해 실행한다.
eval 함수에서는 두 가지를 구현해야 한다.
1. built-in : Shell 에서 처리하는 명령이 소스 코드에 구현돼 있는 명령을 의미한다.
2. Utility : 어딘가에 파일로 존재하는 경우이다. fork exec으로 명령어를 실행한다.
리눅스에서 cd / ls 등 여러 명령어를 사용하는데, 해당 명령어가 excutable file로 존재하면 Utility로 구현됐다고 생각할 수 있다.
Job
Shell이 사용하는 추상화로, 한 개의 command line으로 들어오는 프로세스들을 하나의 job으로 만든다.
어떤 순간에는 최대 한 개의 foreground job 과 0개 이상의 background job으로 구성된다.
job을 하나의 단위로 사용한다.
background job은 자식으로 생성되고, 부모와 함께 수행되지만 키보드를 제어하지는 않는다.
'Computer Science > System Programming' 카테고리의 다른 글
[시스템 프로그래밍] 동적 메모리 (1) | 2022.11.30 |
---|---|
[시스템 프로그래밍] 시그널 (0) | 2022.11.14 |
[시스템 프로그래밍] 프로세스 (1) (0) | 2022.11.06 |
[시스템 프로그래밍] 프로시저 (0) | 2022.10.28 |
[시스템 프로그래밍] 어셈블리어 - 반복문 (0) | 2022.10.24 |
댓글
이 글 공유하기
다른 글
-
[시스템 프로그래밍] 동적 메모리
[시스템 프로그래밍] 동적 메모리
2022.11.30 -
[시스템 프로그래밍] 시그널
[시스템 프로그래밍] 시그널
2022.11.14 -
[시스템 프로그래밍] 프로세스 (1)
[시스템 프로그래밍] 프로세스 (1)
2022.11.06 -
[시스템 프로그래밍] 프로시저
[시스템 프로그래밍] 프로시저
2022.10.28