美文网首页
Linux 进程创建、回收、退出

Linux 进程创建、回收、退出

作者: 二进制人类 | 来源:发表于2022-09-27 10:53 被阅读0次

    进程的创建

    相关API

    创建

    #include <unistd.h>
    /**
     * [fork 创建新的子进程,得到两个进程,子进程会对父进程资源进行完整的拷贝。子进程的资源和父进程的资源是相互独立的]
     * @return  [
     *  1. 失败返回-1且修改errno的值;
        2. 成功会得到两个进程,在父进程和子进程中都有返回:
            1) 父进程返回的是子进程的PID;
            2) 子进程返回的是0;    
            ]
     */
    pid_t fork(void);
    
    pid_t vfork(void);
    

    相同点:

    都用在程序(或者进程)运行期间创建新的进程;

    不同点:

        1. 进程的执行顺序:fork创建子进程后,父子进程随机执行;而vfrok创建子进程后,子进程一定优先于父进程执行;
        2. 空间问题:fork创建的子进程会拷贝一份独立的内存资源,而vfrok创建的子进程和父进程共享资源;
        3. 进程创建的效率:vfrok创建子进程的效率高于fork创建子进程。
        4. 创建子进程执行功能不同:fork创建的子进程执行进程处理函数;而vfork子进程常使用exec函数族去调用其它可执行程序。

    实例

    #include <stdio.h>
    #include <unistd.h>
    
    int main()
    {
        int a = 123;
        pid_t pid;
    
        /* 创建一个子进程 */
        pid = fork();
        if (pid == -1)
        {
            perror("fork");
            return -1;
        }
        else if (pid == 0)
        {
            sleep(1);
            /* 当前进程为子进程 */
            printf("child: %d - %d\n", getpid(), getppid());
            printf("child: %p, a = %d\n", &a, a);
        }
        else
        {
            /* 当前父进程执行 */
            a = 321;
            printf("parent: %d - %d\n", getpid(), getppid());
            printf("parent: %p, a = %d\n", &a, a);
        }
    }
    

    资源回收

    #include <sys/types.h>
    #include <sys/wait.h>
    /**
     * [wait 在父进程中使用,阻塞等待该父进程中的任意一个子进程退出,如果有子进程该父进程不在阻塞并回收退出子进程的资源。]
     * @param  status [是一个int类型指针,用来接收子进程退出的状态信息。 如果不关心退出状态使用NULL]
     * @return        [成功返回退出子进程的PID,失败返回-1且修改errno的值]
     */
    pid_t wait(int *status);
    

    实例

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    int main()
    {
        int a = 123;
        pid_t pid;
        int status;
    
        /* 创建一个子进程 */
        pid = fork();
        if (pid == -1)
        {
            perror("fork");
            return -1;
        }
        else if (pid == 0)
        {
            sleep(2);
            /* 当前进程为子进程 */
            a = 321;
            printf("child: %d - %d\n", getpid(), getppid());
            printf("child : a = %d\n", a);
            exit(1);
        }
        else
        {
            /* 当前父进程执行 */
            printf("parent: %d - %d\n", getpid(), getppid());
            /* 父进程等待子进程的退出,并回收子进程的资源 */
            pid = wait(&status);
            if (pid == -1)
            {
                perror("wait");
                return -1;
            }
            printf("parent: %d, a = %d, status = %d\n", pid, a, status);
        }
    }
    
    #include <sys/types.h>
    #include <sys/wait.h>
    /**
     * [waitpid 等待子进程终止,如果子进程终止了,此函数会回收子进程的资源]
     * @param  pid     [
     *      pid子进程选项参数,有以下情况
            1) pid>0,等待子进程PID等于pid的进程退出,父进程不在阻塞,并回收pid子进程的资源。
            2) pid=-1,父进程等待任意一个子进程退出,父进程不在阻塞并回收退出的子进程资源。
            3) pid=0,等待同一个进程组中的任何子进程退出,如果子进程已经加入了别的进程组,waitpid 不会等待它。
            4) pid<-1,等待进程组号为pid绝对值进程组中任何子进程退出。
            ]
     * @param  status  [指向的空间用来存储子进程退出的状态,和wait的参数一致]
     * @param  options [
     *      指针处理选项:
            0:和wait一致,父进程阻塞,直到有子进程退出才返回。
            WNOHANG:没有任何已经结束的子进程,则立即返回,采用非阻塞模式。
            WUNTRACED:如果子进程暂停了则此函数马上返回,并且不予以理会子进程的结束状态。
            ]
     * @return         [ 
     *  1) 当正常返回的时候,waitpid()返回收集到的已经回收子进程的进程号,和wait函数一致。
        2) 如果设置了选项 WNOHANG,而调用中 waitpid() 发现没有已退出的子进程可等待,则返回0;
        3) 失败返回-1,且修改errno的值。如:当pid 所对应的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid() 就会出错返回,这时errno 被设置为 ECHILD;
        ]
     */
    pid_t waitpid(pid_t pid, int *status, int options);
    

    实例

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    
    int main()
    {
        int a = 123;
        pid_t pid;
        pid_t pid1;
        pid_t pid2;
        int status;
    
        /* 创建一个子进程 */
        pid1 = fork();
        if (pid1 == -1)
        {
            perror("fork");
            return -1;
        }
        else if (pid1 == 0)
        {
            sleep(10);
            /* 当前进程为子进程 */
            a = 321;
            printf("child1 : %d - %d\n", getpid(), getppid());
            printf("child1 : a = %d\n", a);
            exit(0);/* 进程退出 */
        }
    
        pid2 = fork();
        if (pid2 == -1)
        {
            perror("fork");
            return -1;
        }
        else if (pid2 == 0)
        {
            sleep(2);
            /* 当前进程为子进程 */
            a = 333;
            printf("child2 : %d - %d\n", getpid(), getppid());
            printf("child2 : a = %d\n", a);
            exit(0);
        }
    
        /* 当前父进程执行 */
        printf("parent: %d - %d\n", getpid(), getppid());
    #if 0
        pid = waitpid(-1, &status, 0);    /* 等价于wait(&status);阻塞等待任意一个子进程退出 */
    #else
        pid = waitpid(pid1, &status, 0);    /* 指定阻塞等待pid进程退出,父进程才会继续执行 */
    #endif
        if (pid == -1)
        {
            perror("wait");
            return -1;
        }
        printf("parent: %d, a = %d, status = %d\n", pid, a, status);
    }
    

    退出

    #include <stdlib.h>
    /**
     * [exit 用于进程退出;是库函数]
     * @param status [
     * 传递进程退出的状态信息,在父进程中使用wait或者waitpid函数来接收退出状态。
        成功失败可以使用宏定义:EXIT_SUCCESS and EXIT_FAILURE
        ]
     */
    void exit(int status);
    /*系统函数*/
    void _exit(int status);
    

    相同点:

    exit和_exit都用于进程的退出;

    不同点:

    1. exit是库函数,_exit是系统函数;

    2. 缓存是否刷新:exit在退出进程之前会刷新进程中的缓存空间再结束进程,而_exit不会刷新缓存直接结束进程

    函数族

    #include <unistd.h>
    
    extern char **environ;
    
    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[]);
    /*
    功能:
        在进程通过exec函数族来启动可执行程序,可执行程序进程资源会将原进程资源做完整的替换。新进程会使用原来的进行PID、PPID、进程组号 控制终端 根目录当前工作目录 进程信号屏蔽集 未处理信号 ...
    字符说明:
        l和v都表示的可执行程序的执行语句:例如ls -al:
            l    :表示的列表形式,最后一个元素为NULL结束;
                参数arg:可变参数,传递可执行程序的执行命令
                "ls", "-al", NULL
            v    :表示的向量形式,最后一个元素为NULL结束;
                参数argv:指针数组,传递可执行程序的执行命令
                char *argv[] = {"ls", "-al", NULL};
        p    :表示的环境变量中PATH变量值
            所有以p表示的函数,可执行程序存储在PATH环境变量所指定的文件中,可以直接通过可执行程序的文件名称找到。
                参数file:可执行文件的名称 
            没有以p表示的函数,可执行程序可以存储在任意的目录中,可以通过文件的相对路径和绝对路径查找。
                参数path:可执行的文件的路径(相对路径和绝对路径)        
        e    :表示的是环境变量
            所有有参数envp的函数,可以设置环境变量的参数。设置的是可执行程序进程的环境变量参数,envp需要以NULL结束
    
     返回值:
         失败返回-1且修改errno的值   
    
    */
    
    

    相关文章

      网友评论

          本文标题:Linux 进程创建、回收、退出

          本文链接:https://www.haomeiwen.com/subject/ntkqartx.html