프로세스 생성의 목적

  1. 같은 프로그램의 처리를 여러 개의 프로세스가 나눠서 처리하기 위해. - fork() 함수
  2. 전혀 다른 프로그램을 생성하기 위해. - execve() 함수

 


1. fork() 함수

  1. fork() 실행 - 프로세스를 새로 만든다.
  2. 자식 프로세스용 메모리 영역을 작성하고 거기에 부모 프로세스의 메모리를 복사한다.
  3. fork() 함수의 리턴값이 각기 다른 것을 이용하여 부모 프로세스와 자식 프로세스가 서로 다른 코드를 실행하도록 분기한다.

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

static void child()
{
        printf("I'm child! my pid is %d.\n", getpid());
        exit(EXIT_SUCCESS);
}

static void parent(pid_t pid_c)
{
        printf("I'm parent! my pid is %d and the pid of my child is %d.\n", getpid(), pid_c);
        exit(EXIT_SUCCESS);
}

int main(void)
{
        pid_t ret;
        ret = fork();
        if (ret == -1)
                err(EXIT_FAILURE, "fork() failed");
        if (ret == 0) {
                // child process came here because fork() returns 0 for child process
                child();
        } else {
                // parent process came here because fork() returns the pid of newly
                // created child process (> 1)
                parent(ret);
        }
        // shouldn't reach here
        err(EXIT_FAILURE, "shouldn't reach here");
}

// pid_t: 프로세스 번호(pid)를 저장하는 타입(t)이라는 의미

 


2. execve() 함수

  1. 실행 파일을 읽은 다음 프로세스의 메모리 맵에 필요한 정보를 읽어 들인다.
  2. 현재 프로세스의 메모리를 새로운 프로세스의 데이터로 덮어쓴다.
  3. 새로운 프로세스의 첫 번째 명령부터 실행한다.

즉, 전혀 다른 프로그램을 생성하는 경우, 프로세스의 수가 증가하는 것이 아니라, 기존의 프로세스를 별도의 프로세스로 변경하는 방식으로 수행된다.

 

구체적으로 보면 일단 실행 파일을 읽고 프로세스의 메모리 맵에 필요한 정보를 읽어들인다. 실행 파일은 프로세스의 실행 중에 사용하는 코드와 데이터 외에도 아래와 같은 정보가 필요하다.

매핑

-코드를 포함한 데이터 영역의 파일상 오프셋, 사이즈, 메모리맵 시작주소.

-코드 외의 변수 등에서의 데이터 영역에 대한 같은 정보(오프셋, 사이즈, 메모리 맵 시작주소)

-최초로 실행할 명령의 메모리 주소

 

코드 영역과 데이터 영역의 ‘메모리 맵 시작 주소’가 필요한 이유는 cpu에서 실행되는 기계언어 명령은 고급언어로 쓰인 소스코드와는 다르게 특정 메모리 주소를 지정할 필요가 있기 때문이다.

 

c = a + b 코드를 기계언어로 바꾸면 다음과 같이 메모리 주소를 직접 조작하는 명령으로 변환(컴파일) 된다.

이렇게 읽어드린 정보로 위의 매핑 이미지와 같은 구조를 형성한다.

그 후 엔트리 포인트 에서부터 실행한다.

 

더보기
  • 두 줄이 하나의 정보 세트
  • 16진수로 표기
  • .text = 코드 영역, .data = 데이터 영역
  • 메모리 맵 시작 주소: 첫 줄의 네 번째 필드
  • 파일상의 오프셋: 첫 줄의 다섯 번째 필드
  • 사이즈: 둘째 줄의 첫 번째 필드

 

execve

#include <unistd.h>

int execve(const char *filename, char *const argv[], char *const envp[]);


출처: https://www.it-note.kr/157 [IT 개발자 Note]

 

 

fork and exec

  1. 프로세스를 새로 만든다.
  2. 부모 프로세스는 echo hello 프로그램을 생성한 뒤 자신의 프로세스 ID와 자식의 프로세스 ID를 출력하고 종료한다.
  3. 자식 프로세스는 자신의 프로세스 ID를 출력하고 종료한다.
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>

static void child()
{
	char *arg[] = {"/bin/echo", "hello", NULL};
	printf("I'm child! my pid is %d.\n", getpid());
	fflush(stdout);
	execve("/bin/echo", arg, NULL);
	err(EXIT_FAILURE, "exec() failed");
}

static void parent(pid_t pid_c)
{
	printf("I'm parent! my pid is %d and the pid of my child is %d.\n", getpid(), pid_c);
	exit(EXIT_SUCCESS);
}

int main(void)
{
	pid_t ret;
	ret = fork();
	if (ret == -1)
		err(EXIT_FAILURE, "fork() failed");
	if (ret == 0)
	{
		//child process came here because fork() returns 0 for child process
		child();
	} else {
		//parent process came here because fork() returns the pid of newly
		//created child process (>1)
		parent(ret);
	}
	// shouldn't reach here
	err(EXIT_FAILURE, "shouldn't reach here");
}

 

 

https://www.it-note.kr/157

'Linux_Ubuntu' 카테고리의 다른 글

tar 파일 압축 및 해제  (0) 2022.03.10
ubuntu 한글 설정  (0) 2021.06.15
ps 명령어 사용법  (0) 2021.06.11
VI Editor 사용법  (0) 2021.06.11
Ubuntu 18.04 설치 및 환경 셋팅 (RTX 3090, 2080) 및 기타 Tips  (0) 2021.06.11

+ Recent posts