文章

linux系统编程-进程

进程

进程:

​ 程序:死的。只占用磁盘空间。 ——剧本。

​ 进程;活的。运行起来的程序。占用内存、cpu等系统资源。 ——戏。

PCB进程控制块:

  • 进程id
  • 文件描述符表
  • 进程状态: 初始态、就绪态、运行态、挂起态、终止态。
  • 进程工作目录位置
  • *umask掩码
  • 信号相关信息资源。
  • 用户id和组id

CPU和MMU

中央处理器(CPU)

img

内存管理单元MMU

img

进程状态

img

fork函数:

 pid_t fork(void)

创建子进程。父子进程各自返回。父进程返回子进程pid。 子进程返回 0.

getpid(); //获取进程pid
getppid(); //获取父进程pid

循环创建N个子进程

创建子进程后、父子进程都会接着fork()函数继续执行。

image-20240901224106026

image-20240901224034548

循环创建N个子进程模型。 每个子进程标识自己的身份。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
    int i;
    for ( i = 0; i < 5; i++){
        if (fork() == 0)
        break;
    }
    if (i == 5){
        sleep(5);
        printf("i am parent \n");
    }else{
        sleep(i);
        printf("i am %dth child \n",i+1);
    }
    return 0;
}

父子进程

父子进程相同:

刚fork后。 data段、text段、堆、栈、环境变量、全局变量、宿主目录位置、进程工作目录位置、信号处理方式

父子进程不同:

进程id、返回值、各自的父进程、进程创建时间、闹钟、未决信号集

父子进程共享:

读时共享、写时复制。———————— 全局变量。

  1. 文件描述符 2. mmap映射区。

gdb调试:

设置父进程调试路径:set follow-fork-mode parent (默认)

设置子进程调试路径:set follow-fork-mode child

exec函数族:

使进程执行某一程序。成功无返回值,失败返回 -1

int execlp(const char *file, const char *arg, ...);		借助 PATH 环境变量找寻待执行程序

​	参1: 程序名

​	参2: argv0

​	参3: argv1

​	...: argvN

​	哨兵:NULL

int execl(const char *path, const char *arg, ...);		自己指定待执行程序路径。

int execvp();

ps ajx --> pid ppid gid sid 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
    int ret = fork();
    if (ret == 0){
        int fd1 = open("test.txt",O_RDWR|O_CREAT,0666);
        dup2(fd1,STDOUT_FILENO);
        execlp("ps","ps","aux",NULL);
    }else{
        sleep(2);
        printf("i am parent \n");
    }
    return 0;
}

回收子进程

孤儿进程:

父进程先于子进终止,子进程沦为“孤儿进程”,会被 init 进程领养。

僵尸进程:

子进程终止,父进程尚未对子进程进行回收,在此期间,子进程为“僵尸进程”。 kill 对其无效。

wait函数

wait函数: 回收子进程退出资源, 阻塞回收任意一个。

pid_t wait(int *status)

参数:(传出) 回收进程的状态。

返回值:成功: 回收进程的pid

	失败: -1, errno

函数作用1:	阻塞等待子进程退出

函数作用2:	清理子进程残留在内核的 pcb 资源

函数作用3:	通过传出参数,得到子进程结束状态


获取子进程正常终止值:

WIFEXITED(status) --》 为真 --》调用 WEXITSTATUS(status) --》 得到 子进程 退出值。

获取导致子进程异常终止信号:

WIFSIGNALED(status) --》 为真 --》调用 WTERMSIG(status) --》 得到 导致子进程异常终止的信号编号。

waitpid函数

waitpid函数:指定某一个进程进行回收。可以设置非阻塞。waitpid(-1, &status, 0) == wait(&status);

pid_t waitpid(pid_t pid, int *status, int options)

参数:
	pid:指定回收某一个子进程pid

		> 0: 待回收的子进程pid

		-1:任意子进程

		0:同组的子进程。

	status:(传出) 回收进程的状态。

	options:WNOHANG 指定回收方式为,非阻塞。

返回值:

	> 0 : 表成功回收的子进程 pid

	0 : 函数调用时, 参3 指定了WNOHANG, 并且,没有子进程结束。

	-1: 失败。errno

回收子进程

wait:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    pid_t pid , wpid;
    int status;
    pid = fork();
    if (pid == 0){
        printf("i am child ,pid = %d ,going to sleep 10s \n",getpid());
        sleep(10);
        printf("---------------child die ---------\n");
        return 73;
    }else if (pid > 0){
        wpid = wait(&status);
        if(wpid == -1){
            perror("wait error");
            exit(1);
        }
        if (WIFEXITED(status)){  //为真 子进程正常退出
            printf("child exit code : %d \n",WEXITSTATUS(status));
        }else if (WIFSIGNALED(status)){  //为真 子进程被信号终止
            printf("child exit signal : %d \n",WTERMSIG(status));
        }
        printf("parent wait finish : %d \n",wpid);
    }
    return 0;
}

waitpid:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <dirent.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
    int i;
    pid_t pid ,wpid;
    for ( i = 0; i < 5; i++){
        if (fork() == 0)
            break;
    }
    if (i == 5){
        // sleep(5);
        // while ((wpid = waitpid(-1,NULL,WNOHANG)) != -1)
        // {
        //     if (wpid > 0 ){
        //         printf("wait child finish : %d \n",wpid);
        //     }else{
        //         sleep(1);

        //     }
        // }
        while ((wpid = waitpid(-1,NULL,0)) != -1)
        {
            printf("wait child finish : %d \n",wpid);
        }
    }else{
        sleep(i);
        printf("i am %dth child my pid  is %d \n",i+1,getpid());
    }
    return 0;
}

总结:

  • ​ wait、waitpid 一次调用,回收一个子进程。
  • ​ 想回收多个。while
License:  CC BY 4.0