Computer >> 컴퓨터 >  >> 프로그래밍 >> C 프로그래밍

C에서 fork() 및 exec() 익히기:프로세스 생성 및 교체 설명

이 Linuxhint 기사에서는 fork() 및 exec() 함수를 사용하여 프로세스를 생성, 실행 또는 다른 프로세스로 바꾸는 방법을 배웁니다. 이 두 함수에 대한 설명을 살펴보고 해당 구문과 호출 방법을 설명하겠습니다. 또한 두 기능 각각에 대한 간단한 실제 예도 살펴보겠습니다. 그런 다음 포크()와 execv()를 함께 사용하여 프로세스를 생성하고 다른 프로세스로 대체하는 방법을 설명하겠습니다.

C 언어의 Fork() 함수

fork() 함수는 호출 프로세스의 복제본을 만듭니다. 자식 프로세스는 부모 프로세스와 중복되지만 할당된 메모리 영역, PID 등과 같은 특정 속성을 공유하지 않습니다. 다음으로 fork() 함수의 구문을 살펴보겠습니다.

fork() 함수는 상위 프로세스에 하위 프로세스의 PID를 결과로 반환하는 반면, 동일한 호출은 하위 프로세스에 영향을 주지 않고 결과로 0을 반환합니다. 이 메커니즘을 사용하면 조건이 fork()의 반환 값인 "if" 조건을 통해 두 프로세스에서 서로 다른 코드를 실행할 수 있습니다. 다음 개념을 살펴보겠습니다:

if (포크() ==0)
   {
    자식 프로세스의 코드
   }

그렇지 않으면
    {
     상위 프로세스의 코드
    }

이러한 방식으로 상위 프로세스는 "else" 문의 중괄호 사이에 있는 코드를 실행하고, 하위 프로세스는 "if" 문의 코드를 실행합니다.

간단한 예를 통해 이를 살펴보겠습니다. 우리가 보는 다음 코드는 두 개의 무한 루프로 구성됩니다. 상위 프로세스에서 프로그램은 "Write for parent process" 메시지를 표시하는 "else" 문에 해당하는 루프에 빠지고, fork()에 의해 생성된 하위 프로세스에서는 "Write for child process" 메시지를 표시하는 "if" 문에 속하게 됩니다.

#include
#include

무효 메인(){

if (포크() ==0)
   {
    동안 (1){
    printf("자식 프로세스에 쓰기\n");
    수면(5);}
   }

그렇지 않으면
    {
      동안 (1){
     printf("상위 프로세스에 의해 쓰기 \n");
     수면(2);}
    }
}

다음 이미지는 이 코드의 컴파일 및 실행을 보여줍니다. 명령 콘솔에서 볼 수 있듯이 각 프로세스는 서로 다른 코드를 실행합니다.

C에서 fork() 및 exec() 익히기:프로세스 생성 및 교체 설명

C 언어의 ExecXXX() 함수

execXXX() 함수 계열은 실행 중인 프로세스를 새 프로세스로 대체합니다. 새 프로세스의 이미지는 대체되는 프로세스에 할당된 메모리 영역에 복사되며 무엇보다도 해당 PID 및 할당된 리소스가 보존됩니다.

"unistd.h" 헤더에 정의된 이 그룹의 함수는 입력에 따라 다른 호출 방법을 사용하고 "가변" 유형이므로 지정되지 않은 인수 또는 포인터 목록을 이전 프로세스에서 새 프로세스로 전달할 수 있습니다. 다음으로 각 함수의 구문을 살펴보겠습니다.

int execl(const char *path, const char *arg, ...(char  *) NULL );
int execlp(const char *file, const char *arg, ... (char  *) NULL );
int execle(const char *path, const char *arg, ... , (char *) NULL, char     * const envp[] );

int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[],
                    char *const envp[]);

execl(), execle() 및 execv() 함수는 새 프로세스 실행 파일의 절대 경로를 포함하는 문자열에 대한 첫 번째 입력 인수로 포인터를 사용하는 반면, execlp(), execvp() 및 execvpe()는 현재 디렉터리에 있는 파일 이름을 사용합니다. 두 번째 입력은 새 프로세스에 전달하는 인수입니다. 이는 const char *arg 문자열이거나 char *const argv[] 문자열에 대한 포인터 목록이어야 합니다.

이제 execv() 함수를 사용하여 프로세스를 대체하고 한 프로그램에서 다른 프로그램으로 입력 인수를 전달하는 예를 살펴보겠습니다.

이를 위해 우리는 매우 간단한 두 개의 코드를 만듭니다. 하나는 execv() 함수를 호출하여 하위 프로세스를 실행하는 상위 프로세스입니다. execv() 함수는 하위 프로세스를 시작할 때 하위 프로세스가 검색하여 셸에 표시할 문자열 형식으로 두 개의 입력 인수를 전달합니다.

하위 프로세스

자식 프로세스는 "나는 자식 프로세스입니다"라는 메시지를 인쇄하고 부모 프로세스에서 보낸 입력 인수를 검색하여 셸에 표시하는 간단한 코드 조각입니다. 하위 프로세스의 코드는 다음과 같습니다:

 
#include
#include
#include
 
int main(int argc, char *argv[])
{
 printf("나는 자식 프로세스입니다\n\n");
 printf("인수 1:%s\n", argv[1]);
 printf("인수 2:%s\n", argv[2]);
}
 

우리는 이 코드를 컴파일하고 다음과 같이 확장자가 ".bin"인 "하위" 이름 아래의 "문서"에 해당 결과물을 저장합니다:

 
~$ gcc 문서/child.c -o 문서/child.bin
 

이러한 방식으로 하위 실행 파일을 "문서"에 저장합니다. 이 실행 파일의 경로는 상위 프로세스에서 execv()를 호출할 때 입력 인수 경로입니다.

상위 프로세스

상위 프로세스는 execv() 함수를 호출하여 하위 프로세스로 대체하는 프로세스입니다. 이 코드에서는 execv() 함수가 여는 프로세스에 대한 입력 인수를 나타내는 문자열에 대한 포인터 배열을 정의합니다.

다음 그림에서는 문자열에 대한 포인터 배열을 올바르게 만드는 방법을 볼 수 있습니다. 이 경우 4개의 포인터로 구성되며 “arg_Ptr[]”이라고 합니다.

포인터 배열이 정의되면 각 포인터에는 하위 프로세스에 보내는 입력 인수가 포함된 문자열이 할당되어야 합니다. execxx() 함수 사용에 대한 경험상 첫 번째 인수는 실행 파일의 이름과 확장자를 포함하는 문자열이어야 하며 마지막 포인터는 NULL이어야 합니다.

따라서 해당 인수를 문자열 형식으로 각 포인터에 할당합니다.

 
arg_Ptr[0] ="child.bin";
arg_Ptr[1] ="안녕하세요";
arg_Ptr[2] ="프로세스 2";
arg_Ptr[3] =NULL;
 

다음 단계는 실행 파일의 절대 경로를 포함하는 문자열을 첫 번째 인수로 전달하고 문자열 배열 arg_Ptr[]을 두 번째 인수로 전달하여 execv() 함수를 호출하는 것입니다. 다음에서 상위 프로세스의 전체 코드를 볼 수 있습니다:

 
 
#include
#include
#include
#include
#include
 
정수 메인(){
printf("나는 부모 프로세스입니다.");
char *arg_Ptr[4];
arg_Ptr[0] =" child.c";
arg_Ptr[1] ="안녕하세요";
arg_Ptr[2] ="프로세스 2";
arg_Ptr[3] =NULL;
 
execv("/home/linuxhint/Documents/child.bin", arg_Ptr);
}
 

".c" 파일의 경로와 출력 이름을 지정하는 다음 코드를 컴파일합니다.

 
~$ gcc Documents/parent.c -o 패턴
 

그런 다음 출력을 실행합니다:

부모 프로세스는 “나는 부모 프로세스입니다”라는 메시지를 표시하고, 다음 프로세스로 전달되는 각 입력 인수에 문자열을 할당하여 문자열 배열을 생성하고 execv() 함수를 호출합니다.

execv() 함수가 성공적으로 실행되면 "child.bin" 실행 파일이 상위 프로세스를 대체하고 해당 ID와 할당된 메모리를 인수합니다. 따라서 이 작업은 취소할 수 없습니다.

하위 프로세스는 "나는 하위 프로세스입니다"라는 메시지를 표시하고 명령 콘솔에 표시하기 위해 상위 프로세스가 전달한 각 입력 인수를 검색합니다.

C에서 fork() 및 exec() 익히기:프로세스 생성 및 교체 설명

Linux에서 새로운 프로세스를 생성하기 위한 Fork() 및 Execve() 함수의 조합

지금까지 살펴본 것처럼 fork() 함수는 프로세스를 복제하는 반면 execve()는 프로세스를 대체합니다. 이 예에서는 이 두 함수를 함께 사용하여 교체된 복제본에서 새 프로세스를 열 수 있는 방법을 살펴보겠습니다. 이를 위해 이전에 본 두 함수의 코드를 결합하여 fork()가 상위 프로세스를 복제하고 execve()가 이를 실행 파일로 대체합니다. 이 경우 이전 “child.bin” 예제에서 사용한 것과 동일한 것입니다.

이제 확장자가 ".c"인 빈 파일을 가져와서 fork() 함수 예제에서 본 프로그램 코드를 삽입합니다.

이 프로그램에서는 execv() 함수가 이를 "child.bin" 실행 파일로 대체하도록 하위 프로세스의 코드만 수정하고 주요 작업은 fork() 함수 예제와 동일합니다.

이를 위해 execv() 함수 예제에서 main() 함수의 내용을 복사하고 "if" 문의 내용을 이 코드로 바꿉니다. 이제 전체 프로그램이 어떤 모습인지 살펴보겠습니다.

#include
#include

무효 메인(){

if (포크() ==0)
   {
    printf("나는 자식 프로세스입니다\n");
    char *arg_Ptr[5];
    arg_Ptr[0] =" child.c";
    arg_Ptr[1] ="안녕하세요";
    arg_Ptr[2] ="프로세스 2";
    arg_Ptr[3] =NULL;
    execv(/home/linuxhint/Documents/child.bin", arg_Ptr);
   }

그렇지 않으면
    {
      동안 (1){
     printf("

상위 프로세스로 쓰기 \n");
     수면(3);}
    }
}

이러한 방식으로 프로세스는 execv() 함수가 "child.bin" 실행 파일의 프로세스로 대체하는 시스템에 새 프로세스를 생성하여 복제됩니다. 다음으로 이 코드가 컴파일된 이미지를 볼 수 있습니다.

C에서 fork() 및 exec() 익히기:프로세스 생성 및 교체 설명

이미지에서 볼 수 있듯이, fork() 함수는 이를 복제하여 새로운 프로세스를 생성하고, execv() 함수는 이를 "child.bin" 실행 파일로 대체합니다.

결론

이 Linuxhint 기사에서는 Linux에서 새 프로세스를 열기 위해 fork() 및 execv() 함수를 사용하는 방법을 보여주었습니다. 이러한 각 함수, 해당 구문, 입력 및 출력 인수에 대한 간략한 설명을 보여 드렸습니다. 작동 방식을 더 잘 이해할 수 있도록 호출 방법과 각 기능이 수행하는 작업을 학습한 각 기능의 예도 포함했습니다. 이 두 가지 기능을 개별적으로 살펴본 후, 이를 조합하여 Linux에서 새로운 프로세스를 생성하기 위해 C 언어가 제공하는 방법을 구현하는 방법을 설명했습니다.