[프로세스] 프로세스 이해 및 관련 코드 시연

목차

0. 프로세스 개요

1. 프로세스 생성

1.1 프로세스 생성: 포크 기능

1.2 프로세스 대기: wait(), waitpid()

1.3 특수 프로세스: 좀비 프로세스, 고아 프로세스, 데몬 프로세스

1.4 프로세스 종료: exit 및 _exit 함수

1.5 프로세스 종료 정리: atexit 기능

1.6 프로세스 생성: vfork 함수

2. 프로세스 교체: exec 함수 계열

3. 시스템 기능:

요약하다:


0. 프로세스 개요

프로세스 정의

프로그램과 프로세스의 차이점:

  •         프로그램: 디스크에 저장된 정적 실행 파일입니다.
  •         프로세스: 동적이며 메모리에서 실행되는 프로그램의 실행 인스턴스입니다.
  •         프로그램은 명령의 순서화된 집합이고, 프로세스는 프로그램 실행 프로세스이며, 프로세스는 프로그램의 실행 프로세스입니다.
  •         프로세스 생성, 예약, 종료 등 프로세스 변경 상태가 변경됩니다.
  •         프로그램이 실행되는 동안은 프로세스이고, 프로그램이 한 번 실행되지 않으면 프로세스가 생성됩니다.

Linux 시스템에서 프로세스는 트랜잭션을 관리하는 기본 단위입니다.

프로세스는 자신만의 독립적인 처리 환경과 시스템 리소스(프로세서, 메모리, I/O 장치, 데이터, 프로그램)를 갖습니다.

프로세스 상태 및 전환:

프로세스의 전체 라이프사이클은 간단히 세 가지 상태로 나눌 수 있습니다.

준비 상태:

        프로세스는 실행을 위한 모든 조건을 갖추고 있으며 CPU 처리 시간이 할당되기를 기다리고 있습니다.

실행 상태:

        프로세스가 실행되기 위해 CPU를 사용하고 있습니다.

대기 상태:

        프로세스가 특정 실행 조건을 충족하지 않아 일시적으로 실행을 계속할 수 없는 상태입니다.

프로세스 스케줄링 메커니즘:

        타임 슬라이스 회전, 컨텍스트 전환.

        다중 처리란 하나의 프로세스가 실행되고 다른 프로세스가 실행되는 것이 아니라 교대로 실행되는 것을 의미하며, 한 프로세스가 일정 시간 동안 실행되고 일정 시간 동안 다음 프로세스가 실행되는 방식입니다. on 모든 프로세스가 실행된 후 첫 번째 프로세스로 돌아가서 계속 실행하는 식입니다.

프로세스의 세 가지 상태 간의 전환 관계:

 프로세스 제어 블록:

        프로세스 제어 블록은 PCB라고도 불리는 프로세스 정보를 저장하는 데 사용되는 구조입니다.

        OS는 PCB를 기반으로 동시에 실행되는 프로세스를 제어하고 관리합니다. 시스템이 프로세스를 생성하면 이 프로세스와 관련된 PCB 데이터 구조를 저장하기 위해 메모리 공간이 열립니다.

        PCB는 운영체제에서 가장 중요한 레코드형 데이터 구조이다. PCB는 프로세스 진행 상황을 설명하고 프로세스 작동을 제어하는 ​​데 필요한 모든 정보를 기록합니다.

        PCB는 프로세스의 존재를 나타내는 유일한 신호입니다. Linux에서 PCB는 task_struct 구조에 저장됩니다.

        /usr/src/linux-heads....일반/include/linux/sched.h

PCB 구조의 데이터 부분:

일정 데이터:

        프로세스 상태, 플래그, 우선순위, 스케줄링 전략 등

시간 데이터:

        프로세스가 생성된 시간, 사용자 모드의 실행 시간, 커널 모드의 실행 시간 등

파일 시스템 데이터:

        umask 마스크, 파일 설명자 테이블 등

메모리 데이터, 프로세스 컨텍스트, 프로세스 식별(프로세스 번호)

。。。

프로세스 제어:

프로세스 번호:

        각 프로세스는 프로세스 번호로 식별되며 해당 유형은 pid_t이고 프로세스 번호 범위는 0-32767입니다.

        프로세스 ID는 항상 고유하지만 프로세스 ID는 재사용될 수 있습니다. 프로세스가 종료되면 해당 프로세스 ID를 다시 사용할 수 있습니다.

우분투의 현재 시스템에서 열려 있는 모든 프로세스를 확인합니다.

추신 : AJX

PPID: 현재 프로세스의 상위 프로세스의 프로세스 ID입니다.

PID: 현재 프로세스의 프로세스 번호입니다.

PGID: 현재 프로세스가 위치한 그룹의 프로세스 그룹 ID입니다.

COMMAND: 현재 프로세스의 이름

특별 프로세스 번호:

  •         Linux 시스템에서 프로세스 번호는 0부터 시작합니다.
  •         프로세스 번호가 0과 1인 프로세스는 커널에 의해 생성됩니다.
  •         프로세스 번호가 0인 프로세스는 일반적으로 스케줄링 프로세스이며 종종 스왑퍼라고 불립니다.
  •         프로세스 번호 1의 프로세스는 일반적으로 init 프로세스이며 init 프로세스는 모든 프로세스의 조상입니다.
  •         스케줄링 프로세스를 제외하고 Linux의 모든 프로세스는 init 프로세스에 의해 직간접적으로 생성됩니다.

프로세스 ID(PID)

        프로세스를 식별하는 음수가 아닌 정수입니다.

상위 프로세스 ID(PPID)

        Init 프로세스를 제외한 모든 프로세스는 다른 프로세스에 의해 생성되는데, 이 프로세스를 생성된 프로세스의 상위 프로세스라고 하며, 해당 프로세스 번호를 PPID(상위 프로세스 ID)라고 합니다.

프로세스 그룹 번호(PGID)

        프로세스 그룹은 하나 이상의 프로세스 모음입니다. 이들은 서로 연관되어 있으며, 프로세스 그룹은 동일한 단말로부터 다양한 신호를 수신할 수 있으며, 연관된 프로세스는 프로세스 그룹 번호(PGID)를 갖는다.

Linux 운영 체제는 프로세스 ID를 얻기 위해 getpid(), getpgid() 및 getppid()라는 세 가지 함수를 제공합니다.

#include<sys/types.h>

#include<unistd.h>

pid_t getpid(void);

기능: 현재 프로세스의 프로세스 번호를 가져옵니다.

pid_t getppid(void);

기능: 현재 프로세스의 상위 프로세스의 프로세스 번호를 가져옵니다.

pid_t getpgid(pid_t pid);

기능: 현재 프로세스가 위치한 프로세스 그룹의 프로세스 번호를 얻는다.

코드 예:

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

int main()
{
    printf("pid = %d\n", getpid());
    printf("ppid = %d\n", getppid());
    printf("pgid = %d\n", getpgid(getpid()));
    while (1);
    return 0;
}

실행 스크린샷:

1. 프로세스 생성

1.1 프로세스 생성: 포크 기능

포크 기능:

#include<unistd.h>

pid_t 포크(void);

기능: 기존 프로세스를 기반으로 하위 프로세스를 만듭니다.

매개변수:

        없음

반환 값:

        성공:

                >0: 상위 프로세스의 코드 영역을 식별하는 하위 프로세스의 프로세스 번호입니다.

              ==0: 자식 프로세스의 코드 영역입니다.

        실패하다:

                -1: 상위 프로세스로 돌아가면 하위 프로세스가 생성되지 않습니다.

        분기 기능을 사용하여 얻은 하위 프로세스는 상위 프로세스의 복사본이며 상위 프로세스로부터 전체 프로세스의 주소 공간을 상속받습니다.

주소 공간:

        프로세스 컨텍스트, 프로세스 스택, 열린 파일 설명자, 신호 제어 설정, 프로세스 우선순위, 프로세스 그룹 번호 등을 포함합니다. 자식 프로세스에 고유한 유일한 것은 프로세스 번호, 타이머 등입니다. 따라서 포크 기능을 사용하는 데 드는 비용은 매우 높습니다. 

포크 기능이 실행된 후 상위 프로세스와 하위 프로세스의 공간 다이어그램은 다음과 같습니다.

자식 프로세스 만들기

상위 프로세스와 하위 프로세스를 구분하지 않음(권장하지 않음)

코드 예:

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

int main()
{
    //通过fork函数创建一个子进程
    //注意:只要执行了一次fork,就会在原有的进程基础上创建一个新的子进程
    //而且如果fork之后不区分父子进程的代码区,则后面的所有代码都会执行
    fork();
    printf("hadj{\n");
    while (1);
    return 0;
}

실행 스크린샷:

상위 프로세스와 하위 프로세스 구별(권장)

코드 예:

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


int main()
{
    //父子进程是来回交替执行的,谁先谁后不一定。
    pid_t pid;
    pid = fork();
    if (pid < 0)    //创建子进程失败
    {
        perror("fail to fork");
        exit(1);
    }
    else if (pid > 0)   //父进程代码区
    {
        while (1)
        {
            printf("in parent process\n");
            sleep(1);
        }
    }
    else   //子进程代码区(pid == 0)
    {
        while (1)
        {
            printf("in son process\n");
            sleep(1);
        }
    }
    return 0;
}

실행 스크린샷:

상위 프로세스에는 독립적인 주소 공간이 있습니다.

코드 예:

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

int a = 555;

int main()
{
    pid_t pid;
    pid = fork();
    static int  b = 777;
    int c = 888;
    //子进程会复制父进程fork之前的所有内容
    if (pid < 0)
    {
        perror("fail to fork");
        exit(1);
    }
    else if (pid > 0)
    {
        printf("in partent process\n");
        a++;
        b++;
        c++;
        printf("a = %d, b = %d, c = %d\n", a, b, c);
    }
    else
    {
        sleep(1);
        printf("in son process\n");
        printf("a = %d, b = %d, c = %d\n", a, b, c);
    }
    while (1);

    return 0;
}

실행 스크린샷:

 코드 예:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>


int main()
{

    int fd;
    if ((fd = open("file.txt", O_RDONLY)) == -1)
    {
        perror("fail to open");
        exit(1);
    }
    //子进程会继承父进程的一些共有的区域,例如磁盘空间,内核空间。
    //文件描述符的偏移量保存在内核空间中,所以父进程改变偏移量,子进程获取的偏移量是改变之后的。
    pid_t pid;
    pid = fork();

    if (pid < 0)
    {
        perror("fail to fork");
        exit(1);
    }
    else if (pid > 0)
    {
        printf("in parent process\n");
        char  buf[32] = "";
        if (read(fd, buf, 30) == -1)
        {
            perror("fail to read");
            exit(1);
        }
        printf("buf = [%s]\n", buf);
    }
    else
    {
        sleep(1);
        printf("in son process\n");

        char buf[32] = "";
        if (read(fd, buf, 30) == -1)
        {
            perror("fail to read");
            exit(1);
        }
        printf("buf = [%s]\n", buf);

    }
    while (1);
    return 0;
}

실행 스크린샷:

자식 프로세스는 부모 프로세스의 공간을 상속받습니다.

프로세스 중단:

프로세스가 일정 기간 동안 아무런 작업도 수행하지 않는 경우 이를 프로세스 정지라고 합니다.

#include<unistd.h>

unsigned int sleep(초 단위로 서명되지 않음);

기능:

        프로세스는 지정된 시간(초) 동안 일시 중지되며 지정된 시간이 경과하거나 신호가 수신될 때까지 해제되지 않습니다.

반환 값:

        sec에 지정된 시간 동안 프로세스가 정지되면 0을 반환하고, 프로세스가 중단되면 남은 초를 반환한다.

알아채다:

        프로세스가 지정된 시간(초) 동안 일시 중지된 후 프로그램은 즉시 실행되지 않고 시스템은 프로세스를 준비 상태로 전환합니다.

코드 예:

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

int main()
{
        while(1)
        {
                printf("hello world\n");
                sleep(2);
        }
        return 0;
}

실행 스크린샷:

 

1.2 프로세스 대기: wait(), waitpid()

상위-하위 프로세스에는 하위 프로세스의 종료를 기다리는 상위 프로세스와 같은 간단한 프로세스 간 동기화가 필요한 경우가 있습니다.

Linux는 wait() 및 waitpid()라는 두 가지 대기 함수를 제공합니다.

대기 기능

#include<sys/types.h>

#include<sys/wait.h>

pid_t wait(int *status);

기능:

        자식 프로세스가 종료될 때까지 기다립니다. 자식 프로세스가 종료되면 이 함수는 자식 프로세스의 리소스를 회수합니다.

        대기 함수를 호출하는 프로세스는 하위 프로세스 중 하나가 종료되거나 무시할 수 없는 신호를 받을 때까지 일시 중단됩니다.

        호출 프로세스에 하위 프로세스가 없거나 해당 하위 프로세스가 종료된 경우 이 함수는 즉시 반환됩니다.

매개변수:

        상태: 함수가 반환되면 상태 매개변수에는 하위 프로세스가 종료될 때의 상태 정보가 포함됩니다.

                        하위 프로세스의 종료 정보에는 int에 여러 필드가 포함되어 있습니다.

                        매크로 정의를 사용하여 각 필드를 꺼낼 수 있습니다.

                        하위 프로세스는 종료 또는 _exit 함수를 통해 종료 상태를 보낼 수 있습니다.

                        일반적으로 사용되는 매크로는 다음과 같습니다.

                                WIFEXITED(status): 자식 프로세스가 정상적으로 종료되는지 확인합니다.

         WEXITSTATUS(status): 자식 프로세스의 종료 상태 값을 가져옵니다.

         WIFSIGNALED(status): 시그널을 수신하여 자식 프로세스가 종료되었는지 확인합니다.

         WTERMSIG(status): 자식 프로세스를 종료시킨 신호 번호를 가져옵니다.

반환 값:

        성공: 하위 프로세스의 프로세스 번호입니다.

        실패: -1

코드 예:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>


int main()
{
    pid_t pid;
    pid = fork();

    if (pid < 0)
    {
        perror("fail to fork");
        exit(1);
    }
    if (pid > 0)
    {
        //不接收子进程的退出状态
       // wait(NULL);
        //接收子进程退出状态,子进程中必须用exit或_exit函数退出进程时发送退出状态
        int status = 0;
        wait(&status);
        if (WIFEXITED(status) != 0)
        {
            printf("son process return status:%d\n", WEXITSTATUS(status));
        }
        printf("in pratent proces\n");

    }
    else
    {
        int i = 0;
        for (i = 0; i < 5; i++)
        {
            printf("in son process\n");
            sleep(1);
        }
        exit(4);
    }
    return 0;
}

실행 스크린샷:

waitpid 함수

#include<sys/types.h>

#include<sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int 옵션);

기능:

        자식 프로세스가 종료될 때까지 기다립니다. 자식 프로세스가 종료되면 이 함수는 자식 프로세스의 리소스를 회수합니다.

매개변수:

        pid: 지정된 프로세스 또는 프로세스 그룹.

                pid>0: 프로세스 ID가 PID와 동일한 하위 프로세스를 기다립니다.

                pid+0: 동일한 프로세스 그룹의 모든 하위 프로세스를 기다립니다. 하위 프로세스가 다른 프로세스 그룹에 가입한 경우 waitpid는 이를 기다리지 않습니다.

                pid=-1: 자식 프로세스를 기다립니다. 이때 waitpid와 wait는 동일한 효과를 갖습니다.

                pid<-1: 지정된 프로세스 그룹의 모든 하위 프로세스를 기다립니다. 이 하위 프로세스 그룹의 ID는 pid의 절대값과 같습니다.

        status: 하위 프로세스가 종료될 때 상태 정보를 저장합니다.

        옵션: 옵션

                0: 대기와 동일합니다. 상위 프로세스를 차단하고 하위 프로세스가 종료될 때까지 기다립니다.

                WNOHANG: 종료된 자식 프로세스가 없으면 즉시 반환합니다.

                WUNTRACED: 하위 프로세스가 일시 중지된 경우 이 함수는 즉시 반환되고 하위 프로세스의 종료 상태를 무시합니다. (추적 디버깅, 거의 사용되지 않음)

반환 값:

        성공: 상태가 변경된 자식 프로세스의 프로세스 ID를 반환하며, WNOHANG 옵션이 설정되어 있고 pid에 지정된 프로세스가 존재하면 0을 반환한다.

        실패: -1을 반환합니다. pid로 표시된 하위 프로세스가 존재하지 않거나 프로세스가 존재하지만 호출 프로세스의 하위 프로세스가 아닌 경우 waitpid는 오류와 함께 반환되고 errno는 ECHILD로 설정됩니다.

wait(상태) <==> waitpid(-1, 상태, 0)

코드 예:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<wait.h>


int main()
{

    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fail to fork");
        exit(1);
    }
    else if (pid > 0)
    {
        waitpid(pid, NULL, 0);
        printf("in father process\n");
    }
    else
    {
        int i = 0;
        for (i = 0; i < 5; i++)
        {
            printf("in son  process\n");
            sleep(1);
        }
    }
    return 0;
}

 실행 스크린샷:

1.3 특수 프로세스: 좀비 프로세스, 고아 프로세스, 데몬 프로세스

  • 좀비 프로세스(Zombie Process) 프로세스의 실행이 완료되었으나 해당 프로세스가 점유한 자원이 재활용되지 않은 프로세스를 좀비 프로세스라고 한다. 자식 프로세스가 종료되고 부모 프로세스가 자식 프로세스의 자원을 재활용하기 위해 wait나 waitpid 함수를 호출하지 않은 것이 자식 프로세스가 좀비 프로세스가 되는 이유이다.
  • 고아 프로세스(Orphan Process): 상위 프로세스는 종료되지만 하위 프로세스는 종료되지 않습니다.
  • 데몬 프로세스(Daemon process) 데몬 프로세스는 특별한 고아 프로세스로, 터미널과 분리되어 백그라운드에서 실행됩니다.

1.4 프로세스 종료: exit 및 _exit 함수

종료 기능:

#include<stdlib.h>

무효 종료(int 값)

매개변수:

        status: 상위 프로세스에 반환된 매개변수입니다(하위 8비트가 유효함).

                        일반적으로 실패는 0이 아닌 값으로 설정되고 성공은 0으로 설정됩니다.

_exit 기능:

#include void _exit(int 값)

매개변수:

        status: 상위 프로세스에 반환된 매개변수입니다(하위 8비트가 유효함).

                일반적으로 실패는 0이 아닌 값으로 설정되고 성공은 0으로 설정됩니다.

Exit와 _exit 함수의 차이점:

  •         Exit는 라이브러리 함수이고 _exit는 시스템 호출입니다.
  •         exit는 버퍼를 플러시하지만 _exit는 버퍼를 플러시하지 않습니다.
  •         일반적으로 종료를 사용합니다.

 코드 예:

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

void fun()
{
    printf("nihao hangzhou");
    //测试return是带换行\n
   // printf("nihao hangzhou\n");
    
    //主函数中退出进程,子函数中退出当前函数。
    //      return  ;
    //退出一个进程,刷新缓冲区
    //exit(0);  
    //退出一个进程,不刷新缓冲区    
    _exit(0);
    printf("welcoom to binjiang\n");
}
int main()
{
    printf("hello world\n");
    fun();
    printf("hello kitty\n");
    return 0;
}

실행 스크린샷:

스크린샷 반환:

스크린샷 종료:

 

_종료 스크린샷:

 

1.5 프로세스 종료 정리: atexit 기능

프로세스는 atexit 함수를 사용하여 종료하기 전에 종료 함수를 등록할 수 있습니다.

#include<stdlib.h>

int atexit(void (*function)(void));

기능:

        등록 과정이 정상적으로 종료되기 전에 호출되는 함수이며, 등록 과정이 종료되면 등록 함수가 실행된다.

매개변수:

        function: 프로세스가 끝나기 전에 호출될 함수의 진입 주소입니다.

        atexit 함수는 정리 함수를 등록하는 과정에서 여러 번 호출될 수 있으며, 정상 종료 이전에 함수를 호출하는 순서는 등록 순서와 반대이다. 

코드 예:

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


void clear_fun1(void)
{
    printf("perform clear fun1 \n");
}
void clear_fun2(void)
{
    printf("perform clear fun2 \n");
}
void clear_fun3(void)
{
    printf("perform clear fun3 \n");
}
int main()
{
    //atexit在进程结束时才会执行对应的回调函数
    //注意调用顺序是反的
    atexit(clear_fun1);
    atexit(clear_fun2);
    atexit(clear_fun3);
    printf("process exit 3 sec later!!!\n");
    sleep(3);
    return 0;
}

실행 스크린샷:

1.6 프로세스 생성: vfork 함수

vfork 기능

#include<sys/types.h>

#include<unistd.h>

pid_t vfork(무효)

기능:

        vfork 함수와 fork 함수는 모두 기존 프로세스에 새로운 프로세스를 생성하지만 생성되는 하위 프로세스는 다릅니다.

반환 값:

        자식 프로세스가 성공적으로 생성되면 자식 프로세스에는 0이 반환되고, 부모 프로세스에는 자식 프로세스 ID가 반환됩니다.

        오류가 발생하면 -1을 반환합니다.

포크와 vfork 함수의 차이점:

        vfork는 하위 프로세스가 먼저 실행되도록 보장하며, exec 또는 종료를 호출한 후 상위 프로세스가 실행되도록 예약할 수 있습니다.

        vfork는 fork와 같은 자식 프로세스를 생성하지만 부모 프로세스의 주소 공간을 자식 프로세스에 완전히 복사하지는 않습니다. 왜냐하면 자식 프로세스가 즉시 exec(또는 종료)를 호출하므로 주소 공간에 액세스할 수 없기 때문입니다.

        대신, 자식 프로세스에서 exec 또는 종료를 호출하기 전에는 부모 프로세스의 주소 공간에서 실행되고, exec 후에 자식 프로세스는 자체 프로세스 공간을 갖게 됩니다.

하위 프로세스가 상위 프로세스보다 먼저 실행됩니다.

코드 예:

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

int main()
{
    //使用vfork,子进程会先执行,直到子进程执行exit或exec后,父进程才会执行。
    pid_t pid;
    pid = vfork();
    if (pid < 0)
    {
        perror("fail to  vfork");
        exit(1);
    }
    else if (pid > 0)
    {
        while (1)
        {
            printf("in father process\n");
            sleep(1);
        }
    }
    else
    {
        int i = 0;
        for (i = 0; i < 5; i++)
        {
            printf("in son process\n");
            sleep(1);
        }
        exit(0);
    }
    return 0;
}

실행 스크린샷:

 하위 프로세스는 상위 프로세스와 공간을 공유합니다.

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

int a = 10;
int main()
{
//父子进程共享一个空间
    pid_t pid;
    int b = 9;
    pid = vfork();
    if (pid < 0)
    {
        perror("fail to vfork");
        exit(1);
    }
    else if (pid > 0)
    {
        printf("in father process a = %d b = %d\n", a, b);
    }
    else
    {
        a++;
        b++;
        printf("in son process a = %d b = %d\n", a, b);
        exit(0);
    }
    return 0;
}

 실행 스크린샷:

2. 프로세스 교체: exec 함수 계열

Exec 함수 계열은 6개의 Exec 함수로 구성됩니다.

  1. Exec 함수 계열은 프로세스 내에서 다른 프로세스를 시작하는 6가지 방법을 제공합니다.
  2. exec 함수 계열은 지정된 파일 이름이나 디렉터리 이름을 기반으로 실행 파일을 찾을 수 있습니다.
  3. exec 함수를 호출하는 프로세스는 새로운 프로세스를 생성하지 않으므로 exec 호출 전후에 프로세스의 프로세스 번호가 변하지 않으며, 실행하는 프로그램은 완전히 새로운 프로그램으로 대체되고, 새로운 프로그램은 그 곳에서부터 실행을 시작한다. 주요 기능.

exec 함수 계열은 호출 프로세스의 데이터 세그먼트, 코드 세그먼트 및 스택 세그먼트를 대체합니다.

 #include<unistd.h>

int execl(const char *path, const char *arg, .../*(char *) NULL */);

int execlp(const char *file, const char *arg, .../* (char *) NULL */);

int execlv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

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

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

기능:

        주로 명령을 실행하는 데 사용되는 프로세스에서 다른 프로그램을 실행합니다.

매개변수:

        경로: 명령 또는 프로그램의 경로입니다.

        l: l을 갖는 함수인 경우 해당 명령이나 프로그램이 각 매개변수를 거쳐 전달되며, 마지막은 끝을 나타내는 NULL이다.

                예: "ls","-l",NULL

        v: v가 있는 함수인 경우 해당 명령이나 프로그램은 포인터 배열을 통해 전달되며, 포인터 배열의 마지막 요소는 NULL 플래그로 종료됩니다.

                char *str[] = {"ls", "-l", NULL};

        p: p가 없는 함수인 경우 첫 번째 매개변수는 현재 명령이나 프로그램의 절대 경로를 전달해야 합니다.

              p가 있는 함수인 경우 첫 번째 매개변수는 절대 경로 또는 상대 경로일 수 있습니다.

반환 값:

        실패: -1

코드 예:

#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<unistd.h>


int main()
{
    pid_t pid;
    pid = fork();
    if (pid < 0)
    {
        perror("fail to fork");
        exit(1);
    }
    else if (pid > 0)
    {
        printf("in father process\n");
        wait(NULL);
        printf("the soon process has quied\n");
    }
    else
    {
        printf("in son process\n");
#if 0
        if (execl("/bin/ls", "ls", "-l", NULL) == -1)
        {
            perror("fail to execl");
            exit(1);
        }
#endif
#if 0
        if (execlp("ls", "ls", "-l", NULL) == -1)
        {
            perror("fail to execlp");
            exit(1);
        }
#endif
#if 0
        char* str[] = { "ls", "-l",NULL };
        if (execv("/bin/ls", str) == -1)
        {
            perror("fail to execv");
            exit(1);
        }
#endif
#if 0
        if (execlp("./myshell.sh", "./myshell.sh", NULL) == -1)
        {
            perror("fail to execlp");
            exit(1);
        }
#endif
#if 1
        if (execlp("./myshell.sh", "./myshell.sh", NULL) == -1)
        {
            perror("fail to execlp");
            exit(1);
        }
#endif
#if 0
        if (execlp("./hello", "./hello", NULL) == -1)
        {
            perror("fail to execl");
            exit(1);
        }
#endif
#if 0
        if (execl("./hello", "./hello", NULL) == -1)
        {
            perror("fail to execl");
            exit(1);
        }
#endif

        printf("hello world\n");
    }
    return 0;
}
80, 1          Bot

프로세스가 exec를 호출한 후 프로세스 ID 외에도 프로세스는 다음과 같은 특성도 변경되지 않은 상태로 유지합니다.

  • 상위 프로세스 번호
  • 프로세스 그룹 번호
  • 제어 터미널
  • 루트 디렉토리
  • 현재 작업 디렉토리
  • 프로세스 신호 마스크 세트
  • 처리되지 않은 신호
  • .....

3. 시스템 기능:

#include<stdlib.h>

int system(const char *명령);

기능:

        시스템은 fork 함수를 호출하여 자식 프로세스를 생성합니다. 자식 프로세스는 exec를 호출하여 start /bin/sh -c string 매개변수 문자열 string이 나타내는 명령을 실행합니다. 명령이 실행된 후 호출 프로세스로 반환됩니다. .

매개변수:

        실행할 명령의 문자열입니다.

반환 값:

        command가 NULL인 경우 system() 함수는 0이 아닌 값(보통 1)을 반환합니다.

        System()은 /bin/sh를 호출할 때 실패하면 127을 반환하고 다른 실패 이유로 인해 -1을 반환합니다.

알아채다:

        시스템 호출이 성공하면 쉘 명령을 실행한 후 반환 값이 반환됩니다. 반환값은 1, 127, -1이 될 수 있으므로 errno를 다시 확인하여 실행이 성공했는지 확인하는 것이 가장 좋습니다.

코드 예:

#include<stdio.h>
#include<stlib.h>

int main()
{
    system("clear");
    system("ls -l");
    system("./hello");
    system(. / myshell.sh");

        return 0;
}

요약하다:

        이 장에서는 프로세스의 개념, 생성 및 사용을 소개합니다. 프로세스 관리의 핵심 원칙을 이해함으로써 시스템 리소스를 더 효과적으로 활용 및 제어하고, 동시 작업을 구현하고, 효율적인 애플리케이션을 구축할 수 있습니다. 프로세스의 개념과 기술에 대한 깊은 이해를 통해 보다 안정적이고 확장 가능한 시스템 아키텍처를 설계하고 여러 프로세스 간의 통신 및 동기화 문제를 해결할 수 있습니다.

        이 블로그가 애플리케이션 개발 중 애플리케이션 프로세스 관리의 중요성을 더 잘 이해하고 이해하는 데 도움이 되기를 바랍니다. 읽어 주셔서 감사합니다!        

추천

출처blog.csdn.net/crr411422/article/details/131501849