포크와 exec의 차이점


199

의 차이점은 무엇입니까 fork와는 exec?


3
포크, exec 및 기타 프로세스 제어 기능에 대한 자세한 내용은 yolinux.com/TUTORIALS/ForkExecProcesses.html
Jonathan Fingland

9
@Justin 우리는 SO가되고 싶은 때문에 질문을 프로그래밍하기위한가는 곳.
paxdiablo

4
@ Polaris878 : 아, 이제 그렇습니다! : D
Janusz Lenar

그래서 fork기본적으로 복제되는 : O
세바스찬 Hojas

답변:


364

새로운 프로세스를 시작할 수있는 매우 간단한 방법을 제공한다는 점에서 UNIX 의 사용 forkexec예시는 UNIX의 정신입니다.

fork호출은 기본적으로 동일, 현재 프로세스의 중복 만드는 거의 모든 방법. 모든 구현이 복사되는 것은 아니지만 (예 : 일부 구현의 리소스 제한) 가능한 한 가까운 복사본을 만드는 것이 좋습니다.

새 프로세스 (자식)는 다른 프로세스 ID (PID)를 가져오고 이전 프로세스 (부모)의 PID를 상위 PID (PPID)로 갖습니다. 두 프로세스가 이제 정확히 동일한 코드를 실행하고 있기 때문에 반환 코드를 통해 어느 쪽이 fork자식인지 0으로, 부모가 자식의 PID를 얻는 지 알 수 있습니다. 물론 이것은 fork호출이 작동 한다고 가정합니다. 그렇지 않으면 자식이 생성되지 않고 부모가 오류 코드를 얻습니다.

exec호출은 기본적으로 현재 프로세스 전체를 새로운 프로그램으로 대체하는 방법입니다. 프로그램을 현재 프로세스 공간으로로드하고 진입 점에서 실행합니다.

그래서, fork그리고 exec종종 현재 프로세스의 자식으로 실행하는 새로운 프로그램을 얻을 순서로 사용된다. 쉘은 일반적으로 find쉘 포크 와 같은 프로그램을 실행하려고 할 때마다이를 수행합니다 . 그런 다음 자식은 find프로그램을 메모리에 로드하여 모든 명령 행 인수, 표준 I / O 등을 설정합니다.

그러나 그것들을 함께 사용할 필요는 없습니다. 예를 들어, 프로그램에 부모 코드와 자식 코드가 모두 포함되어있는 경우 프로그램을 fork자체적 으로 수용 exec할 수 있습니다 (작업에주의를 기울여야하며 각 구현에는 제한이있을 수 있음). 이것은 fork부모가 다시 듣기로 돌아가는 동안 TCP 포트와 특정 복사본을 수신하여 특정 요청을 처리하는 데몬에 꽤 많이 사용되었습니다 .

마찬가지로, 그들은이 완료 알고 프로그램은 필요하지 않는 다른 프로그램 실행하려면 fork, exec다음 wait아이에 대한합니다. 자녀를 프로세스 공간에 직접로드 할 수 있습니다.

일부 UNIX 구현에는 forkCOW (Copy-On-Write)를 사용 하는 최적화 된 기능 이 있습니다. 이것은 fork프로그램이 해당 공간에서 무언가를 변경하려고 시도 할 때까지 프로세스 공간의 복사를 지연시키는 요령 입니다. 이것은 단지 사용하는 프로그램에 유용 fork하지 exec가 전체 프로세스 공간을 복사 할 필요가 없습니다에.

이 경우 exec 됩니다 다음 호출 fork(이 대부분 일 것입니다), 그 프로세스 공간에 쓰기를 발생시키고 그 다음 자식 프로세스를 위해 복사됩니다.

전체 exec호출 패밀리 ( execl, execleexecve)가 있지만 exec여기서는 문맥 상 호출 중 하나를 의미합니다.

다음 다이어그램 fork/execbash셸을 사용하여 ls명령 으로 디렉토리를 나열하는 일반적인 작업을 보여줍니다 .

+--------+
| pid=7  |
| ppid=4 |
| bash   |
+--------+
    |
    | calls fork
    V
+--------+             +--------+
| pid=7  |    forks    | pid=22 |
| ppid=4 | ----------> | ppid=7 |
| bash   |             | bash   |
+--------+             +--------+
    |                      |
    | waits for pid 22     | calls exec to run ls
    |                      V
    |                  +--------+
    |                  | pid=22 |
    |                  | ppid=7 |
    |                  | ls     |
    V                  +--------+
+--------+                 |
| pid=7  |                 | exits
| ppid=4 | <---------------+
| bash   |
+--------+
    |
    | continues
    V

52

fork()현재 프로세스를 두 개의 프로세스로 나눕니다. 다시 말해서, 프로그램을 생각하기 쉬운 멋진 선형은 갑자기 하나의 코드를 실행하는 두 개의 별도 프로그램이됩니다.

 int pid = fork();

 if (pid == 0)
 {
     printf("I'm the child");
 }
 else
 {
     printf("I'm the parent, my child is %i", pid);
     // here we can kill the child, but that's not very parently of us
 }

이것은 당신의 마음을 날려 버릴 수 있습니다. 이제 두 프로세스에 의해 거의 동일한 상태가 실행되는 코드가 있습니다. 하위 프로세스는 fork()호출이 중단 된 위치부터 시작하여 프로세스를 생성 한 프로세스의 모든 코드와 메모리를 상속합니다 . 유일한 차이점은 fork()부모 또는 자녀인지 알려주 는 리턴 코드입니다. 부모 인 경우 반환 값은 자식의 id입니다.

exec이해하기 좀 더 쉽게, 당신은 말할 exec대상 실행 파일을 사용하여 프로세스를 실행하면 두 개의 프로세스 같은 코드를 실행하거나 동일한 상태를 상속이 없습니다. @Steve Hawkins가 말한 것처럼 현재 프로세스에서 대상 실행 파일을 실행 exec한 후에 사용할 수 있습니다 fork.


6
이 조건 때이기도 pid < 0하고, fork()호출이 실패
조나단 Fingland

3
그것은 전혀 염두에 두지 않습니다 :-) 두 개의 프로세스에 의해 실행되는 하나의 코드는 공유 라이브러리 또는 DLL이 사용될 때마다 발생합니다.
paxdiablo 2016 년

31

Marc Rochkind의 "Advanced Unix Programming"의 일부 개념 은 fork()/ 의 다른 역할 exec(), 특히 Windows CreateProcess()모델에 익숙한 사람 에게 다른 역할을 이해하는 데 도움이되었다고 생각합니다 .

프로그램은 디스크에있는 일반 파일에 보관 지침과 데이터의 모음입니다. (1.1.2 프로그램, 프로세스 및 스레드)

.

프로그램을 실행하기 위해 커널은 먼저 프로그램이 실행되는 환경 인 새로운 프로세스 를 작성하도록 요청받습니다 . (1.1.2 프로그램, 프로세스 및 스레드)

.

프로세스와 프로그램의 차이점을 완전히 이해하지 않고서도 exec 또는 fork 시스템 호출을 이해하는 것은 불가능합니다. 이 용어가 처음 인 경우에는 1.1.2 절을 다시 검토하십시오. 지금 진행할 준비가 되었다면 한 문장으로 구별 할 것입니다. 프로세스는 명령, 사용자 데이터 및 시스템 데이터 세그먼트와 런타임에 획득 한 기타 많은 리소스로 구성된 실행 환경입니다. 반면 프로그램은 프로세스의 명령 및 사용자 데이터 세그먼트를 초기화하는 데 사용되는 명령 및 데이터를 포함하는 파일입니다. (5.3 exec시스템 호출에서)

프로그램과 프로세스의 차이점을 이해하면 동작 fork()exec()기능을 다음과 같이 요약 할 수 있습니다.

  • fork() 현재 프로세스의 복제본을 만듭니다
  • exec() 현재 프로세스의 프로그램을 다른 프로그램으로 대체

(이것은 본질적으로 paxdiablo의 훨씬 더 자세한 답변의 단순화 된 '인형 용'버전입니다 )


29

포크는 호출 프로세스의 사본을 작성합니다. 일반적으로 구조를 따릅니다 여기에 이미지 설명을 입력하십시오

int cpid = fork( );

if (cpid = = 0) 
{

  //child code

  exit(0);

}

//parent code

wait(cpid);

// end

(자식 프로세스 텍스트 (코드), 데이터, 스택의 경우 호출 프로세스와 동일) 자식 프로세스는 if 블록에서 코드를 실행합니다.

EXEC는 현재 프로세스를 새로운 프로세스의 코드, 데이터, 스택으로 대체합니다. 일반적으로 구조를 따릅니다 여기에 이미지 설명을 입력하십시오

int cpid = fork( );

if (cpid = = 0) 
{   
  //child code

  exec(foo);

  exit(0);    
}

//parent code

wait(cpid);

// end

(exec 호출 후 유닉스 커널은 자식 프로세스 텍스트, 데이터, 스택을 지우고 foo 프로세스 관련 텍스트 / 데이터로 채 웁니다) 따라서 자식 프로세스는 다른 코드 (foo의 코드 {부모와 동일하지 않음})입니다


1
그것은 질문과 관련이 없지만 위의 코드가 자식 프로세스가 코드를 먼저 끝내면 경쟁 조건을 일으키지 않습니까? 이 경우 부모 프로세스는 아이가 스스로 종료되기를 영원히 기다리는 것입니다.
stdout

7

새로운 자식 프로세스를 만들기 위해 함께 사용됩니다. 먼저 호출 fork하면 현재 프로세스 (자식 프로세스)의 복사본이 생성됩니다. 그런 다음, exec하위 프로세스 내에서 호출되어 상위 프로세스의 사본을 새 프로세스로 "대체"합니다.

프로세스는 다음과 같습니다.

child = fork();  //Fork returns a PID for the parent process, or 0 for the child, or -1 for Fail

if (child < 0) {
    std::cout << "Failed to fork GUI process...Exiting" << std::endl;
    exit (-1);
} else if (child == 0) {       // This is the Child Process
    // Call one of the "exec" functions to create the child process
    execvp (argv[0], const_cast<char**>(argv));
} else {                       // This is the Parent Process
    //Continue executing parent process
}

2
7 번째 줄에서 exec () 함수가 자식 프로세스를 생성한다고 언급되어 있습니다. fork ()가 이미 자식 프로세스를 생성하고 exec () 호출이 방금 생성 된 새 프로세스의 프로그램을 대체하기 때문에
cbinder

4

fork ()는 fork () 호출 직후부터 시작하여 새 자식에서 실행하면서 현재 프로세스의 복사본을 만듭니다. fork () 후에는 fork () 함수의 반환 값을 제외하고는 동일합니다. (자세한 내용은 RTFM을 참조하십시오.) 그러면 공유 파일 핸들을 통한 경우를 제외하고 두 프로세스가 다른 프로세스를 방해 할 수 없으므로 더 확산 될 수 있습니다.

exec ()는 현재 프로세스를 새로운 프로세스로 바꿉니다. exec ()가 현재 자식 프로세스를 바꾸지 않고 다른 자식 프로세스를 시작하는 경우 exec ()가 fork () 뒤에 오는 것을 제외하고는 fork ()와는 아무런 관련이 없습니다.


3

주요 차이점 fork()exec()그 인

fork()시스템 호출은 현재 실행중인 프로그램의 복제를 만듭니다. 원래 프로그램은 fork () 함수 호출 후 다음 코드 줄로 실행을 계속합니다. 클론은 다음 코드 줄에서 실행을 시작합니다. http://timmurphy.org/2014/04/26/using-fork-in-cc-a-minimum-working-example/ 에서 얻은 다음 코드를보십시오.

#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv)
{
    printf("--beginning of program\n");
    int counter = 0;
    pid_t pid = fork();
    if (pid == 0)
    {
        // child process
        int i = 0;
        for (; i < 5; ++i)
        {
            printf("child process: counter=%d\n", ++counter);
        }
    }
    else if (pid > 0)
    {
        // parent process
        int j = 0;
        for (; j < 5; ++j)
        {
            printf("parent process: counter=%d\n", ++counter);
        }
    }
    else
    {
        // fork failed
        printf("fork() failed!\n");
        return 1;
    }
    printf("--end of program--\n");
    return 0;
}

이 프로그램은 fork()ing 전에 카운터 변수를 0으로 설정하여 선언 합니다. 포크 호출 후, 우리는 두 개의 프로세스를 병렬로 실행하며 둘 다 자체 버전의 카운터를 증가시킵니다. 각 프로세스는 완료되어 종료됩니다. 프로세스가 병렬로 실행되기 때문에 어떤 프로세스가 먼저 완료되는지 알 방법이 없습니다. 이 프로그램을 실행하면 아래에 표시된 것과 비슷한 내용이 인쇄되지만 결과는 실행마다 다를 수 있습니다.

--beginning of program
parent process: counter=1
parent process: counter=2
parent process: counter=3
child process: counter=1
parent process: counter=4
child process: counter=2
parent process: counter=5
child process: counter=3
--end of program--
child process: counter=4
child process: counter=5
--end of program--

exec()시스템 호출의 가족은 코드의 또 다른 조각으로 프로세스의 현재 실행중인 코드를 대체합니다. 프로세스는 PID를 유지하지만 새로운 프로그램이됩니다. 예를 들어 다음 코드를 고려하십시오.

#include <stdio.h> 
#include <unistd.h> 
main() {
 char program[80],*args[3];
 int i; 
printf("Ready to exec()...\n"); 
strcpy(program,"date"); 
args[0]="date"; 
args[1]="-u"; 
args[2]=NULL; 
i=execvp(program,args); 
printf("i=%d ... did it work?\n",i); 
} 

이 프로그램은 execvp()함수를 호출하여 코드를 날짜 프로그램으로 바꿉니다. 코드가 exec1.c라는 파일에 저장된 경우 실행하면 다음 출력이 생성됩니다.

Ready to exec()... 
Tue Jul 15 20:17:53 UTC 2008 

프로그램은 Execc to exec () 라인을 출력합니다. . . 그리고 execvp () 함수를 호출 한 후 코드를 날짜 프로그램으로 바꿉니다. ― 라인에 유의하십시오. . . 이 시점에서 코드가 교체되었으므로 작동 했습니까?”라는 메시지가 표시되지 않습니다. 대신“date -u”실행 결과를 봅니다.


1

여기에 이미지 설명을 입력하십시오fork():

실행중인 프로세스의 사본을 작성합니다. 실행중인 프로세스를 상위 프로세스 라고하며 새로 작성된 프로세스를 하위 프로세스 라고 합니다 . 둘을 구별하는 방법은 반환 값을 보는 것입니다.

  1. fork() 부모 프로세스에서 자식 프로세스의 프로세스 식별자 (pid)를 반환

  2. fork() 자식에서 0을 반환합니다.

exec():

프로세스 내에서 새 프로세스를 시작합니다. 기존 프로세스를 대체하여 새 프로세스를 현재 프로세스에로드합니다.

fork()+ exec():

새 프로그램을 시작할 때 먼저 fork()새 프로세스를 만든 다음 exec()프로그램 바이너리를 실행해야합니다 (예 : 메모리에로드 및 실행).

int main( void ) 
{
    int pid = fork();
    if ( pid == 0 ) 
    {
        execvp( "find", argv );
    }

    //Put the parent to sleep for 2 sec,let the child finished executing 
    wait( 2 );

    return 0;
}

0

프라임 예는을 이해 fork()하고 exec()개념은이다 , 사용자는 일반적으로 system.The 쉘에 로그인 한 후 실행하는 명령 인터프리터 프로그램의 첫 번째 단어 해석 명령 줄을 A와 명령 이름

많은 명령 들어, 포크 와 자식 프로세스의 임원 이름이 명령에 매개 변수로 명령 행의 나머지 단어를 치료와 관련된 명령.

쉘은 명령의 세 가지 유형을 할 수 있습니다. 첫째, 명령 은 소스 코드 (예 : C 프로그램)를 컴파일하여 생성 된 객체 코드가 포함 된 실행 파일 일 수 있습니다 . 둘째, 명령은 일련의 셸 명령 줄이 포함 된 실행 파일 일 수 있습니다. 마지막으로, 명령은 내부 쉘 명령 일 수 있습니다 (실행 파일 ex-> cd , ls 등 대신).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.