目录
一、进程的概述
1、程序和进程的区别
2、单道和多道程序设计
3、并行和并发的区别
4、进程控制块(PCB)
5、进程的状态
二、进程号PID
1、获取进程号的函数
2、获取父进程的ID
3、获取进程组的ID
三、 fork创建进程
1、fork函数
2、fork出来的子进程和父进程之间的关系
3、子进程 复制 父进程的资源(各自独立)
编辑4、父子进程同时运行
编辑
5、父进程 给子进程 足够的准备时间时
四、特殊的进程
1、孤儿进程(无危害)
2、僵尸进程(有害)
3、守护进程
五、父进程回收子进程的资源
1、wait函数
编辑 2、waitpid函数
六、创建多个子进程
1、创建2个子进程出现的问题
2、防止子进程 创建孙进程
七、 进程相关
1、终端
2、进程组
3、会话
编辑 4、创建守护进程
编辑八、 vfork创建子进程
1、vfork函数说明
2、vfork函数和fork函数的区别
编辑九、exec函数族
案例1:在代码中使用execl执行ls命令
案例2:在代码中使用execlp执行ls命令
案例3:在代码中使用execvp执行ls命令
编辑 案例4:vfork和exec配合使用,会为子进程开辟新的空间
一、进程的概述
可执行程序运行起来后(没有结束之前),它就成为了一个进程。程序是存放在存储介质上的一个可执行文件,而进程是程序执行的过程。进程的状态是变化的,其包括进程的创建、调度和消亡。程序是静态的,进程是动态的。
1、程序和进程的区别
程序 静态的 占磁盘空间(存放在存储介质上的一个可执行文件)
进程 动态的 (调度、执行、消亡),占内存空间。(进程是程序执行到结束间的这个过 程)
2、单道和多道程序设计
单道程序设计 所有进程一个一个排队执行。若A阻塞,B只能等待,即使CPU处于空闲状 态。这种模型在系统资源利用上及其不合理,大部分已被淘汰了。
多道程序设计 在计算机内存中同时存放几道相互独立的程序,它们在管理程序控制之 下,相互穿插的运行。当下常见CPU为纳秒级,由于人眼的反应速度是毫秒级,所以看似同时在运行。
而多道程序设计必须有硬件基础作为保证。时钟中断(强制让进程让出cpu资源)即为多道程序设计模型的理论基础。
3、并行和并发的区别
并行(微观)和并发(宏观)都是多个任务同时执行(多道程序)。
并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行(微观上同时执行)(多核)
并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执 行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时 间分成若干段,使多个进程快速交替的执行(单核 )
4、进程控制块(PCB)
进程运行时,内核为每个进程分配一个PCB(进程控制块),维护进程相关的信 息,Linux内核的进程控制块是task_struct结构体。 PCB存在于进程的内核空间里面。系统会为每一个进程分配一个进程ID,其类型为pid_t(非负整数) ,进程的状态,有就绪、运行、挂起、停止等状态。进程状态切换时需要保存和恢复的一些CPU寄存器。进程是系统分配资源的基本单位。
5、进程的状态
进程的三大状态:就绪态、执行态、等待态
- 就绪态:执行条件全部满足,等待CPU的执行调度
- 执行(运行)态:正在被CPU调度执行
- 等待态:不具备CPU调度执行的执行条件,等待条件满足。
状态机:
ps命令查看进程信息:
| 选项 | 含义 |
| -a | 显示终端上的所有进程,包括其他用户的进 程 |
| -u | 显示进程的详细状态 |
| -x | 显示没有控制终端的进程 |
| -w | 显示加宽,以便显示更多的信息 |
| -r | 只显示正在运行的进程 |
查看进程状态:ps -aux
stat中的参数意义如下:
以树状显示进程:pstree
二、进程号PID
每个进程都由一个进程号来标识,其类型为 pid_t(整型),进程号的范围:0~32767。 进程号总是唯一的,但进程号可以重用。当一个进程终止后,其进程号就可以再次使用 。
- 进程号(PID): 标识进程的一个非负整型数
- 父进程号(PPID):父进程号
- 进程组号(PGID): 进程组是一个或多个进程的集合。
1、获取进程号的函数
头文件:
#include<sys/type.h>
#include<unistd.h>
函数:
pid_t getpid(void);
功能: 获取本进程号(PID)
参数: 无
返回值: 本进程号
2、获取父进程的ID
#include<sys/type.h>
#include<unistd.h>
pid_t getppid(void);
功能: 获取调用此函数的进程的父进程号(PPID)
参数: 无
返回值: 调用此函数的进程的父进程号(PPID)
3、获取进程组的ID
#include<sys/type.h>
#include<unistd.h>
pid_t getpgid(pid_t pid);
功能: 获取进程组号(PGID)
参数: pid:进程号
返回值: 参数为 0 时返回当前进程组号,否则返回参数指定的进程的进程组号
查看父子进程号:ps -ef
查看所有进程号:ps -ajx
getchar();防止进程结束。
三、 fork创建进程
1、fork函数
系统允许一个进程创建新进程,新进程即为子进程,子进程还可以创建新的子进程,形成进 程树结构模型。
#include<sys/types.h>
#include<unistd.h>
pid_t fork(void);
功能: 用于从一个已存在的进程中创建一个新进程,新进程称为子进程,原进程称为父进程。
参数: 无
返回值: 成功:子进程中返回 0,父进程中返回子进程 ID。pid_t,为整型。 失败:返回-1。
失败的两个主要原因:
1)当前的进程数已经达到了系统规定的上限,这时 errno 的值被设置为 EAGAIN。
2)系统内存不足,这时 errno 的值被设置为 ENOMEM
2、fork出来的子进程和父进程之间的关系
使用fork函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间。 地址空间: 包括进程上下文、进程堆栈、打开的文件描述符、信号控制设定、进程优 先级、进程组号等。 子进程所独有的只有它的进程号,计时器等。因此,使用fork函数的代价是很大的 。
父子进程从fork后开始继续执行。父子进程是同时运行,空间独立,子进程复制父进程的所有空间,谁先运行不确定。
#include <stdio.h> #include <unistd.h> int main(int argc,char *argv[]) { //创建子进程 pid_t pid=fork(); if(pid<0) { perror("创建失败\n"); } else if(pid==0) { printf("%d为子进程\n",getpid()); } else if(pid>0) { printf("%d为父进程\n",getpid()); } getchar(); return 0; }