fork함수

신준우·2023년 6월 2일
0

시스템 프로그래밍

목록 보기
5/12

이전 내용 복습

  • 간단한 쉘을 만들었었다
  • psh1.c라는 명령어, 옵션등, 프로그램을 입력해서 새로운 프로세스 시행하는 기능!

여기서 의문점이 생긴다

  • psh1으로 충분한걸까?
  • 명령이 실행된 즉시 종료되어버린다
  • 새로운 명령을 바로 받을수는 없을까?
  • 다시 쉘을 시행해야하는 불편함이 있다
  • 물론, 가장 간단하게는....
    - 새 프로세스를 시행한다
    - 새로운 프로세스가 프로그램을 실행하게 한다
  • 얼마나 많은 프로그램이 실행하고 싶은지와 관계없이,
    프로그램의 수 만큼, 프로세스를 생성하면 그만~

새로운 프로세스 시행하려면?

fork()가 답이 될 수 있다

  • fork를 호출하면 프로세스는 자기 스스로를 복제한다
fork
PURPOSE 프로세스를 생성한다
INCLUDE #include <unistd.h>
USAGE pid_t result = fork(void)
ARGS 없음
RETURNS -1: if error, 0: child process인 경우, pid: parent process인 경우 child의 pid
  • fork 실행전의 프로세스는 Parent, fork 실행 후의 프로세스는 Child라고 한다.
    - Child는 Parent프로세스와 똑같은 코드와 똑같은 데이터를 가진다

그럼 fork는 커널에서 어떤 방식으로 시행되는걸까?

  • fork가 호출되면
  1. 새로운 메모리 청크와 커널 데이터 구조를 할당
  2. 기존의 프로세스 (코드와 데이터)를 새로운 프로세스에 복사한다
  3. 새로운 프로세스를 실행중인 프로세스들에 추가한다
  4. 프로세스의 기능을 두 프로세스에 반환해준다

그럼 간단한 포크를 알아보자

forkdemo1.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char* argv[]){
	int ret_from_fork, mypid;		//int형 변수 ret_from_fork, mypid 
    
    mypid = getpid();		//getpid함수를 사용해서 mypid
    printf("Before: my pid is %d\n", mypid);		// 가져온 pid를 출력, 현재 프로세스 id 확인
    
    ret_from_fork = fork();		// fork함수를 호출해서 ret_from_fork에 
    							// 현재 프로세스를 복제한다
    sleep(1);		//프로세스 실행을 1초동안 일시 중단
    
    printf("After: my pid is %d, fork() said %d\n", getpid(), ret_from_fork);
    // 이게 뭘 출력하는걸까?
    // getpid(): 현재 프로세스의 id값
    // ret_from_fork: fork()함수의 반환값, 즉 자식프로세스의 ID혹은 0을 출력한다
}

간단한 fork 함수에 대한 이해를 위한 예제이다.
한번 실행화면도 확인해볼까?

다음과 같이 실행됨을 확인할수 있다.

  • 현재 프로세스의 id는 3806
  • fork가 진행된 후, 즉 자식프로세스의 id는 3807
  • 이후 자식프로세스가 시행되며 현재 프로세스의 id는 3807, 현재 실행중인 프로세스의 id는 0으로 출력됨

forkdemo2.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char* argv[]){	
	printf("my pid is %d\n", getpid());		//현재 프로세스의 id출력
    
    //첫번째 fork함수 호출
    fork();		// 현재 프로세스는 복제, 부모와 자식 프로세스가 생성.
    			// 다음 줄로 진행, 자식프로세스도 다음줄로 진행
    
    // 두번째 fork 호출
    fork();		// 각각 부모와 자식 프로세스는 다시 복제됨
    			// 2^2승, 즉 4개의 프로세스 생성
                // 생성된 프로세스들이 다음 줄로 진행됨
    
    // 세번째 fork 호출
    fork();		// 각 부모 프로세스와 자식프로세스는 다시 복제
    			// 2^3, 즉 8개의 프로세스 생성
    printf("my pid is %d\n", getpid());		//각 프로세스의 id출력
}

코드만 보면 무슨소리인지 이해하기가 힘들것이다

그림과 함께 봐보자

이와 같이, fork함수가 처음 실행되면 부모프로세스(1), 과 자식프로세스(1)이 생성된다

fork함수가 두번째로 실행되면 각 부모프로세스(1), 자식프로세스(1)의 자식프로세스들이 생성됨,
그러므로 자식 프로세스들이 2개가 생김

.
.
.
이렇게 계속 반복해서 3번!

실행화면으로도 확인해보자!

총 출력하는 프로세스의 id 개수를 살펴보자

총 9개! 부모프로세스 1개와 fork로 인해 생성된 자식프로세스 8개로 총 9개가 된다!

이 코드 또한, fork의 실행방식을 보여준다!

forkdemo3.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char* argv[]){
		int fork_rv;		//fork_rv라는 int형 변수 선언
        printf("Before: my pid is %d\n", getpid());		// 현재 실행중인 프로세스의 id를 가져옴
        fork_rv = fork();	//fork를 통해서 fork_rv에 id값 저장
        if(fork_rv == -1)		//만약! fork_rv값이 -1이라면, 즉 fork를 하는데에 오류가 생긴다면
        	perror("fork");		//'fork'라는 에러 메세지를 출력
        else if(fork_rv == 0)		//만약! fork_rv값이 0이라면 child process라는것을 의미한다!
        	printf("I am the child. my pid = %d\n", getpid());		// 그러므로 값을 출력
        else		//나머지 경우에는?
        	printf("I am the parent. my child is %d\n", fork_rv); //parent값이 출력된다
}

자, 이것도 fork를 이해하기위한 예제이다
실행 화면을 먼저 봐볼까?

  • 보다시피, 현재 실행중인 프로세스의 id값을 먼저 출력하게된다
  • 현재 id값을 출력
  • 현재 프로세스 id값 출력

자, 슬슬 세가지 예제 코드를 보면서 헷갈릴것이다

fork함수에 대해 다시 복기해보자

  • fork() 함수의 반환값이 -1인 경우: fork가 정상적으로 실행되지 않았을 경우
  • fork() 함수의 반환값이 0인 경우: fork할 프로세스가 child프로세스일 경우
  • fork() 함수의 반환값이 child process의 pid일 경우: parent 프로세스를 fork하려는 경우이다

이 점들을 다시 확인하면서 예제 코드를 보면 더 도움 될것이다

쉘 만들기!

우리는 쉘을 만들기 위한 요소들에 대해 확인하고 있다.

마지막으로 쉘을 만들었을때는

https://velog.io/@shinkoh98/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EB%A5%BC-%EC%8B%A4%ED%96%89%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95

이 링크의 방법을 통해 프로그램을 실행시키기만 하는 쉘을 만들었었다!

이번 포스트에서 fork함수를 통해 새로운 프로세스를 만들 수 있게 되었다.

  • 새로운 프로세스 만들기
    - fork()

  • 프로그램을 실행하는법
    - execvp()

  • 부모 프로세스가 자식 프로세스가 특정 명령을 실행하는동안 기다리게 하는 방법
    - wait()

wait 함수를 추가해서 좀 더 완벽한 셀을 만들어보자!!

profile
보안

0개의 댓글