5 Preliminary Study of Linux Process


Preface (including table of contents)


Simple process creation

/**
 * @author IYATT-yx
 * @brief 创建进程
 */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
    
    
    // fork创建子进程,子进程的虚拟地址空间和父进程一样(pid不一样)
    // 不可确定父进程和子进程谁先执行
    pid_t pid = fork();
    // 父进程中fork的返回值为子进程的pid
    if (pid > 0)
    {
    
    
        printf("我是父进程,我的pid为: %d ,我的儿子的pid为: %d\n", getpid(), pid);
    }
    // 子进程中fork的返回值为0
    else if (pid == 0)
    {
    
    
        printf("我是子进程,我的pid是: %d ,我父亲的pid是: %d\n", getpid(), getppid());
    }
    else
    {
    
    
        perror("fork");
    }
    
}
/**
 * @author IYATT-yx
 * @brief 创建多进程
 */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
    
    
    int i;
    for (i = 0; i < 3; ++i)
    {
    
    
        pid_t pid = fork();
        // 防止子进程再创建子进程
        if (pid == 0)
        {
    
    
            break;
        }
    }

    // 每次循环创建一个子进程对应一个循环次数
    if (i == 0)
    {
    
    
        printf("我是子进程1: pid = %d\tppid = %d\n", getpid(), getppid());
    }
    else if (i == 1)
    {
    
    
        printf("我是子进程2: pid = %d\tppid = %d\n", getpid(), getppid());
    }
    else if (i == 2)
    {
    
    
        printf("我是子进程3: pid = %d\tppid = %d\n", getpid(), getppid());
    }
    // 最后一次循环后,再次对i自增,不再满足循环条件,停止创建子进程,此时对应的是父进程
    else if (i == 3)
    {
    
    
    	// 可能出现父进程比子进程先执行完,而终端在父进程结束后可能认为程序结束了,就会切回终端
    	// 然后出现切回终端后继续执行子进程并将要打印输出的内容显示到切回后的命令提示符后
    	// 所以让父进程sleep 1秒,最后执行
    	sleep(1);
        printf("我是父进程: pid = %d\n", getpid());
    }
}

exec family of functions
specific function information is available mancommand inquiry

       int execl(const char *pathname, const char *arg, ... (char  *) NULL */);
       int execlp(const char *file, const char *arg, ... (char  *) NULL */);
       int execle(const char *pathname, const char *arg, ... (char *) NULL, char *const envp[] */);
       int execv(const char *pathname, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[], *const envp[]);
  • Replace the content of .text in the child process, let the parent and child process perform irrelevant operations
  • Call another program in one program
/**
 * @author IYATT-yx
 * @brief exec族函数实践示例
 */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
    
    
    pid_t pid = fork();
    if (pid > 0)
    {
    
    
        sleep(1);
        // 常用于执行系统命令
        execlp("pwd", "", NULL);
        // execlp执行成功,则后面的代码替换掉,不执行
        // 如果执行失败,则继续往下,不需要去判断返回值
        perror("execlp");
        return -1;
    }
    if (pid == 0)
    {
    
    
        // 常用于执行自己的程序,和 execlp 参数差不多
        /**
         * @param 执行程序的绝对路径
         * @param 占位参数任意设定内容
         * @param 指定执行程序的参数
         * @param 以NULL结尾
         */
        execl("/bin/ls", "", "-lh", ".", NULL);
        perror("execl");
        return -1;
    }
}

Process recycling

  • Orphan process: The parent process is over, while the child process is still running. The init process will inherit the parent process of the child process (a process ends, to release the system resources it occupied, and the PCB of the child process can only be released by the parent process , So there is a mechanism for init to succeed the parent process)
  • Zombie process: The child process is over, and the parent process is still running, but the parent process has not released the child process PCB, this child process is now a zombie process.
/**
 * @author IYATT-yx
 * @brief 孤儿进程
 */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main(void)
{
    
    
    pid_t pid = fork();
    if (pid > 0)
    {
    
    
        printf("我是父进程 pid = %d\n", getpid());
    }
    if (pid == 0)
    {
    
    
        sleep(1);
        printf("我是子进程,原父进程已死,当前父进程 pid = %d\n", getppid());
    }
}

Run result:
Insert picture description here
Look at the process with pid 8 is init
Insert picture description here

/**
 * @author IYATT-yx
 * @brief 僵尸进程
 */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdbool.h>

int main(void)
{
    
    
    pid_t pid = fork();
    if (pid > 0)
    {
    
    
        while (true)
        {
    
    
            printf("我是父进程 pid = %d\n", getpid());
            sleep(1);
        }
    }
    else if (pid == 0)
    {
    
    
        printf("我是子进程,父进程的pid = %d\n", getppid());
    }
}

After running this program, open another terminal to query the name of the program. The first is the running parent process, and the second is the dead child process (defunct dead), but the resources have not been recycled (the parent process is busy , The child process cannot be recycled)
Insert picture description here

/**
 * @author IYATT-yx
 * @brief wait回收进程
 */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdbool.h>

int main(void)
{
    
    
    pid_t pid = fork();
    if (pid > 0)
    {
    
    
        printf("我是父进程\n");

        int status;
        pid_t wPid = wait(&status);
        // return/exit结束
        // w if exited
        if (WIFEXITED(status))
        {
    
    
            // w exit status
            printf("exit code: %d\n", WEXITSTATUS(status));
        }
        // kill信号终止
        // w if signaled
        else if (WIFSIGNALED(status))
        {
    
    
            // w term sig
            printf("signal: %d\n", WTERMSIG(status));
        }
        printf("父: pid = %d,回收进程的pid = %d\n", getpid(), wPid);
        
    }
    else if (pid == 0)
    {
    
    
        // // 测试使用 kill 命令杀死进程
        // while (true)
        // {
    
    
        //     printf("子: pid = %d\tppid = %d\n", getpid(), getppid());
        //     sleep(1);
        // }

        sleep(3);
        printf("子: pid = %d\tppid = %d\n", getpid(), getppid());
        exit(66);
    }
}

Use waitrecycled child process, a recovery can only be called once, and you can not specify the recovery process of a child, the death of one can only recover a. Wait by blocking the way, we have been waiting for the child to die, as long as the child's death, it immediately recovered.

/**
 * @author IYATT-yx
 * @brief waitpid回收进程
 */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdbool.h>

int main(void)
{
    
    
    pid_t pid = fork();
    if (pid > 0)
    {
    
    
        printf("我是父进程\n");

        int status;
        /**
         * @brief 
         *       返回值:
         *              > 0: 被回收进程的pid
         *              -1: 无子进程
         *              == 0: 第三个参数为 WNOHANG, 且子进程正在运行
         * @param . 要回收的进程的pid
         * @param . 回收进程的结束方式
         * @param . 设置为0则阻塞, WNOHANG就是非阻塞
         */ 
        pid_t wPid = waitpid(pid, &status, 0);
        // return/exit结束
        // w if exited
        if (WIFEXITED(status))
        {
    
    
            // w exit status
            printf("exit code: %d\n", WEXITSTATUS(status));
        }
        // kill信号终止
        // w if signaled
        else if (WIFSIGNALED(status))
        {
    
    
            // w term sig
            printf("signal: %d\n", WTERMSIG(status));
        }
        printf("父: pid = %d,回收进程的pid = %d\n", getpid(), wPid);
        
    }
    else if (pid == 0)
    {
    
    
        // // 测试使用 kill 命令杀死进程
        // while (true)
        // {
    
    
        //     printf("子: pid = %d\tppid = %d\n", getpid(), getppid());
        //     sleep(1);
        // }

        sleep(3);
        printf("子: pid = %d\tppid = %d\n", getpid(), getppid());
        exit(66);
    }
}

Guess you like

Origin blog.csdn.net/weixin_45579994/article/details/112777564