Search
Duplicate
👩🏻‍💻

[운영체제] 프로세스의 생성(fork() system call)

간단소개
context switch를 하기 위해 동기화(synchronization)을 잘 해야하는데,(동시성 제어) 이 전에 프로세스는 어떻게 생성해야하는지를 알아야한다! (다음 시간엔 프로세스간 통신 (IPC)에 대해 학습할 예정!)
팔만코딩경 컨트리뷰터
ContributorNotionAccount
주제 / 분류
Operating System
운영체제
개발지식
Scrap
태그
9 more properties
유닉스 계열 OS에서, 새로운 프로세스의 생성반드시 fork() system call을 이용하게 되어있다.
⇒ 자식 프로세스는 보통 “a copy of the address space”해서 만든다.
== 현재 나의(부모의) 프로세스의 주소 공간을 복사해서 만든다.
—> 부모 프로세스와 자식 프로세스는 fork() 시스템 콜 이후 계속 실행이 되는데, return code에서 차이를 보인다.
fork()의 return code가 0 이면 —> 자식 프로세스
0이 아닌 pid값(운영체제에서 부여한 값)이면 → 부모 프로세스
**pid? → process id
위의 소스코드(main.c)를 컴파일 하면 a.out이라는 실행파일(프로그램)이 나오게 된다. 이 a.out을 메모리에 로드 하면,(PCB블록에 관련 정보 생성도 완료) 프로세스가 생성이 된다. 위 프로세스에서,
위의 실행 파일이 메모리에 로드된 프로세스가 P0라고 할때, P0가 CPU를 점유한 상태에서 pid = fork() 명령어를 실행하면, 현재 상태의 P0와 동일한 P1이 메모리에 복사된다.(현재 PCB 상태도 그대로 복사) 복사 이후, 그 다음 줄인 printf()가 실행되고 나면 P0를 할당 해제 되는데, PC는 P1의 PCB를 받아, fork()명령어 이후인 printf()문을 실행하게 되어, 위의 소스 코드 main.c를 컴파일 하여 실행해보면
Hello, Process!
Hellp, Process!
라는 출력 결과를 얻을 수 있다.
위에서 설명한 내용 대로, printf()문에서 fork에서 반환 받은 pid를 출력해 보면, P0(부모 프로세스)에서는 fork()값이 반환한 pid가 출력되고, P1(자식프로세스)에서는 0이 출력되는 결과를 볼 수 있다.
Hello, Process! 1004
Hello, Process! 0
fork() system call을 하면,
부모 프로세스의 Adress Space를 그대로 복제하고, 부모는 자기 할일을 계속 함
(예제에서 fork로 자식 프로세스를 생성한 이후 printf()를 출력함)
혹은,
자식 프로세스 생성 한 이후, 자식 프로세스가 run되는 동안 wait()할 수도 있다.
(wait() 시스템 콜을 통해, 자식 프로세스가 terminated 상태가 될 때까지 레디큐에서 나와, 웨이트큐에서 대기할 수 있다.)
위와 같은 코드를 실행하면, pid = fork()에서 부모 프로세스 P0와 자식 프로세스 P1의 분기가 일어나게 되고, if (pid >0)의 조건 문에 의해서, P0는 점유하고 있던 CPU를 반납하고 wait queue에서 대기하게 된다. P1(자식 프로세스)이 cpu를 점유하면, 자식 프로세스의 pid는 0이므로, wait() system call을 호출하지 않고 printf()문을 호출하게 된다. P1이 terminated 되면, wait queue에서 대기 중이던 P0에 인터럽트를 걸게 되고, P0가 다시 CPU를 점유해 printf()문을 호출한다.
Hello, Process! 0
Hello, Process! 2556
⇒ Parent: value = 5
자식 프로세스내의 전역변수만 +15 증가되었을 뿐, 부모 프로세스에는 영향을 미치지 못한다.
⇒ 총 8개의 프로세스가 생성 된다.
⇒ 16개
fork();를 4번 한것과 같은 문제 이다.
각 명령어가 위 처럼 부모 프로세스로부터 자식 프로세스들을 만들어내고, 이는 2^4개의 프로세스를 만들어낸다.
⇒ execlp가 뭐지?
유닉스 계열 OS에서는 프로세스의 생성은 반드시 fork() system call을 통해 이뤄진다.
그런데, a.out이라는 실행 프로그램의 launcher 프로그램이고, 이 프로그램은 다른 프로그램을 실행하는 것을 목적으로 할때, execlp라는 시스템콜을 호출해, fork() 시스템 콜을 통해 복제된 자식 프로세스(a.out)에 실행하려고 하는 프로그램(b.out)을 덮어 씌울 수 있다.
현재 위의 코드에서 execlp를 호출해서 ls라는 프로그램(커맨드)를 자식 프로세스에 복사한다. → ls가 실행된다. printf(”LINE J\n”);는 실행되지 않는다. 덮어씌워졌으므로.
⇒위의 출력 결과는 터미널에서 ls 커맨드를 실행했을 때 얻는 출력 화면을 얻을 수 있다.
fork()로 복제된 자식 프로세스에서(pid == 0), 자신의 pid를 얻기 위해(알기 위해) getpid()를 호출.
아랫쪽 else if 문 내의 printf()에서 출력되는 결과들은 모두 parent process의 pid 이다.