프로그래밍 공부
작성일
2022. 11. 5. 13:54
작성자
WDmil
728x90

프로세스를 생성하고 종료하는 시스템 호출/표준 라이브러리 함수

함수 의미
fork 자신과 완전히 동일한 프로세스를 생성한다.
exec계열 지정한 실행 파일로부터 프로세스를 생성한다.
exit 종료에 따른 상태값을 부모 프로세스에게 전달하며 프로세르를 종료한다.
atexit exit로 프로세스를 종료할 때 수행할 함수를 등록한다.
_exit atexit로 등록한 함수를 호출하지 않고 프로세스를 종료한다.

프로세스 생성 함수

#include <unistd.h>
#include <stdlib.h>
#incldue <sys/types.h>

void cleanupaction(void);

main()
{
// 프로세스 식별번호 저장
    pid_t pid;
    int i;
    for(i=0; i<3; i++)
    {
        printf("befor fork [%d]\n",i);
        sleep(1);
    }

// 자식 프로세스 생성
    pid = fork();
    if (pid>0) {
        for( ; i<7; i++) {
            printf("parent [%d]\n",i);
            sleep(1);
        }
// 함수 등록
        atexit(cleanupaction);
    }
    else if(pid ==0) {
        for( ; i<5 ; i++)  {
            printf("chiuld [%d]\n", i);
            sleep(1);
//ls 실행하여 새로운 프로세스 생성
            execl("/bin/ls","ls","-l",(char *)0);
        }
    }
    else("/bin/ls","ls","-l",(char*)0);
    }
}
else {
    printf("fail to fork child process\n");
}
    exit(0);
/* end of main*/

void cleanupaction(void)
{
    print("clean-up-action\n");
}

Fork()함수 : 프로세스를 복제하여 완전히 동일한 프로세스를 생성한다.

#include <sys/type.h>
#include <unistd.h>

pid_t fork(void);

fork 호출이 성공하여 자식 프로세스가 만들어지면, 부모 프로세스에서는 자식 프로세스 ID가 반환되고

자식 프로세스에서는 0을 반환

fork 호출이 실패하여 자식 프로세스가 만들어지지 않으면 부모 프로세스에서는 -1이 반환

 

프로세스는 실행 파일로 존재하는 프로그램으로부터 생성되는 것이 일반적이나, fork를 사용하면 실행 중인 프로세스를 복제하여 새로운 프로세스를 생성할 수 있음.

 

부모 프로세스와 자식 프로세스

  • fork를 호출하여 새로운 프로세스를 생성할 때, fork를 호출하는 쪽을 부모 프로세스라고 하고 새로 생성된 쪽을 자식 프로세스 라고한다.
  • 부모 프로세스와 자식 프로세스는 서로 다른 프로세스 이다.
    • 프로세스 식별번호(PID) 가 서로 다르다.
    • 자식 프로세스의 부모 프로세스 식별번호(PPID)는 자신을 생성한 부모 프로세스가 된다.
  • 자식 프로세스는 부모 프로세스가 fork를 호출하던 시점의 상태를 그대로 물려받는다.
    • 프로그램 코드
    • 프로그램 변수에 저장되어 있는 데이터 값
    • 하드웨어 레지스터의 값
    • 프로그램 스택의 값 등등
  • fork 호출 이후에 부모와 자식 프로세스는 자신들의 나머지 프로그램 코드를 수행한다.

fork를 호출하는 프로그램의 구조

fork를 호출하는 시점을 기준으로, fork를 호출한 이후에 부모 프로세스가 할 일과 자식 프로세스가 할 일을 구분한다.

fork의 반환 값으로 부모 프로세스와 자식 프로세스를 구분한다.

pid = fork(); /* fork  호출이 성공하면 자식 프로세스가 생성된다.*/

if(pid == 0)
/* 자식 프로세스가 수행할 부분*/

else if(pid >0)
/* 부모 프로세스가 수행할 부분 */

else
/* fork 호출이 실패할 경우 수행할 부분 */

 

프로세스 생성 함수 (exec 계열)

경로 이름 또는 파일 이름으로 지정한 실행 파일을 실행하여 프로세스 생성한다.

#include <unistd.h>

extern char **environ;

int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
path 실행 파일의 경로로 상대 경로와 절대 경로 모두 사용할 수 있다.
file 경로 이름이 아닌 실행 파일의 이름이다.
반환값 호출이 성공하면 호출하는 프로세스에는 반환 값을 받을 수 없다. 만약 함수 호출 후-1이 반환되면 이는 함수 호출이 실패했음을 의미한다.
arg path나 file로 지정한 실행 파일을 실행할 떄 필요한 명령어 라인의 옵션과 인자이다. 한 개 이상을 지정할 수 있으며 마지막 인자는 반드시 NULL 포인터로 지정해야 한다.
argv arg와 같은 의미를 가지나 문자열 포인터의 배열로 형태가 다르다. 배열의 마지막은 NULL문자열로 끝나야 한다.

exec 계열 함수의 구분

  • 함수 이름에 p가 있고 없고의 차이
    • p가 없으면
      • 경로(path)로 실행 파일을 지정한다.
    • p가 있으면
      • 실행 파일의 이름만 지정한다.
  • 경로를 지정하는 경우 (p가 없을 경우)
    • 지정한 (상대/절대) 경로에서 해당 파일을 찾는다.
  • 파일의 이름만 지정하는 경우 (p가 있는 경우)
    • 쉘 환경변수 PATH에서 지정한 디렉터리를 차례대로 검색하여 찾는다.
      • 예)$ printenv PATH <- 환경변수 PATH의 값을 출력한다.

exec 계열의 함수는 지정한 실행 파일로부터 프로세스를 생성한다.

  • fork 는 실행 중인 프로세스로부터 새로운 프로세스를 생성한다.

exec 계열의 함수의 사용 예

호출 프로세스와 피 호출 프로세스

  • 호출 프로세스( caller process )
    • exec 를 실행하는 프로세스
  • 피호출 프로세스 ( calle process )
    • exec에 의해 생성되는 프로세스

exec를 성공적으로 호출한 결과

  • 호출 프로세스는 종료된다.
  • 호출 프로세스가 메모리 영역을 피호출 프로세스가 차지한다.
  • 호출 프로세스 PID를 피호출 프로세스가 물려받는다.

exec계열을 사용한 프로세스 생성

 

  fork exec계열
프로세스의 원본 부모 프로세스를 복제하여 새로운 프로세스를 생성한다. 지정한 프로그램(파일)을 실행하여 프로세스를 생성한다.
셸 명령줄의 프로그램인자 새롭게 지정할 수 없고 부모 프로세스의 것을 그대로 사용한다. 필요할 경우 적용할 수 있다.
부모( 또는 호출 ) 프로세스의 상태 자식 프로세스를 생성한 후에도 자신의 나머지 코드를 실행한다. 호출이 성공할 경우 호출(Caller)프로세스는 종료된다.
자식( 또는 피호출) 프로세스의 메모리 상의 위치 부모 프로세스와 다른곳에 위치한다. 호출 프로세스가 있던 자리를 피호출 프로스세스가 물려받는다.
프로세스 생성 후 자식( 또는 피호출) 프로세스의 프로그램 코드의 시작지점 fork 호출 이후 부터 수행된다. 프로그램의 처음부터 수행된다.
프로세스 식별 번호 (PID) 자식 프로세스는 새로운 식별 번호를 할당받는다. 호풀 프로세스의 식별 번호를 피호출 프로세스가 물려받는다.
프로세스의 원본인 파일에 대한 권한 부모 프로세스를 복제하므로 상관없다. 실행 파일에 대한 실행 권한이 필요하다.

fork와 exec의 비교(2)

  • Fokr
    • 자신과 동일한 자식 프로세스만 생성할 수 있다.
    • 다른 종류의 프로세스를 생성할 수 없다.
    • 자식 프로세스를 생성하더라도 자신은 종료되지 않는다.
  • exec
    • 자신과 다른 종류의 프로세스를 생성할 수 있다.
    • 새로운 프로세스를 생성하면 자신은 종료된다.

 

fork와 exec를 함께 사용하기

  • fork를 호출하여 자식 프로세스를 생성 한 후에 자식 프로세스가 exec를 호출하여 새로운 프로세스를 생성한다.
  • 결과적으로 부모 프로세스는 종류가 다른 자식 프로세스를 생성하고 자신 역시 나머지 작업을 계속 할 수 있다.

프로세스 생성 함수 (exec)

#include <unistd.h>
#include <stdio.h>
main()
{
    printf("befor executing ls - l\n")
    execl("/bin/ls","ls","-l",(char *)0);
    printf("after executing ls -l\n");
}

for와 exec를 같이 사용

 #include <unistd.h>
#incldue <sys/types.h>

main()
{
    pid_t pid();

    printf("hello!\n")

    pid = fork();

    if(pid > 0) { /* parent process */
        printf("parent\n");
        sleep(1);
    }
    else if(pid == 0)
{ /* child process */
        printf("child\n");
        execl("/bin/ls", "ls", "-l", (char *)0);
        printf("fail to execute ls \n");
    }
    else
    printf("parent: fail to fork\n");
    printf("bye!\n");
}

부모프로세스는 자식 프로세스의 생존 여부와 상관 없이 나머지 일을 수행, 자식 프로세스가 exec를 호출하여 새로운 프로세스 생성 후, 자식 프로세스는 종료 됨.

 

프로세스 생성 함수 exit

프로세스를 종료하면서 부모 프로세스에게 종료와 관련된 상태 값을 넘김

#include <stdlib.h>

void exit(int status);
status 부모 프로세스에게 전달되는 상태 값으로 0~255(1바이트)의 값이 사용된다.
반환값 없음
  • exit는 프로세스를 의도적으로 종료시킨다.
  • 이외에 프로세스가 종료하는 경우는
    • 더이상 수행할 문장이 없거나
    • main 함수 내에서 return 문을 수행할 떄 이다.
  • status의 값은 0~255 사이의 값으로 각각에 대한 정해진 의미가 없다.
  • 프로그램 작성자가 임의로 정해서 사용한다.

프로세스 생성 함수 atexit

프로세스가 exit를 호출하여 종료할 때 수행되는 함수들을 등록한다.

#incldue <stdlib.h>

int atexit(void (*function)(void));
function atexit로 등록할 함수의 이름이다.
반환값 호출이 성공하면 0을 반환하고, 실패하면 0이 아닌 값을 반환한다.
  • function
    • 함수의 이름으로 함수는 void function(void); 형으로 정의되어야 한다.
  • 종료 시 마무리 작업 (clean-up-action)
    • 프로세스가 종료할 때 깔끔한 마무리를 위해 수행해야 하는 작업들
    • 최대 32개까지 등록할 수 있다. (실제 실행 순서는 등록 순서의 역순)
#include <unistd.h>
#include <stdlib.h>

void func1(void);
void func2(void);

main()
{
    printf("hello!\n");
    atexit(func1);
    atecit(func2);

    printf("bye!\n");
    exit(0);
}
void func1(void) { printf("func1\n"); }
void func2(void) { printf("func2\n"); }

프로세스 생성 함수 _exit

exit 함수와 같지만 clean-up-action 을 수행하지 않는다.

#include <unistd.h>

void _exit(int status);
status 부모 프로세스에게 전달되는 상태 값으로 0~255의 값이 사용된다.
반환값 없음

_exit 는 atexit로 claen-up-action에 해당하는 함수들을 등록해 놓았떠라도 종료 할 때 이를 수행하지 않는다.

 

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

void func1(void);
void func2(void);

main()
{
    printf("hello\n");
    atexit(func1);
    atexit(func2);

    printf("bye!\n");
    _exit(0);
}
void func1(void) { printf("func1\n"); }
void func2(void) { printf("func2\n"); }

 

728x90