Linux 进程
本次内容1.理解进程概念了解PCB2.学习进程状态学会创建进程掌握僵尸进程和孤儿进程及其形成原因和危害3.了解进程调度Linux进程优先级理解竞争性与独立性理解并行与并发4.理解C内存空间分配规律了解进程内存映像和应用程序区别认识地址空间一 进程1.什么是进程定义运行中的程序程序是静态的代码进程是动态的执行实例程序就像食谱进程像厨师按照食谱做饭的过程核心特点独立性每个进程有独立的地址空间并发性多个进程可以同时运行通过CPU时间片轮换2. 为什么需要进程1.资源分配操作系统以进程为单位分配CPU内存等资源2. 多任务管理通过进程隔离避免程序间互相干扰例如浏览器崩了不影响音乐软件3.PCB1.什么是PCB定义操作系统为每个进程维护的一个数据结构记录进程的关键信息作用操作系统用来记录进程所有状态信息的数据结构管理进程PCB与进程的关系类似档案1.进程与PCB同时存在PCB是进程存在的唯一标准2.PCB随进程的创建而存在进程终止二销毁3.根据PCB里的状态和优先级决定进程的优先级进程生命周期创建 - 运行 - 阻塞 / 就绪 - 终止2.PCB包含内容信息内容类比进程标识符进程ID(PID)父进程ID(PID)学生的学号老师的工号状态运行态就绪态阻塞态等待I/O学生状态上课吃饭程序计数器下一条要执行的指令地址书签寄存器值CPU寄存器快照进程切换时恢复暂停游戏时保存的进度内存分配页表 堆栈指针等分配表文件描述符进程打开的文件列表学生借阅的图书清单4.task_structLinux中的PCB1.Linux如何实现PCB内核源码中的task_struct**Linux用这个结构体表示PCB定义在include/linux/sched.h2.如何查看进程的task_structps -aux//查看进程列表用户态视角的简化信息5.进程的声生命周期与PCB关系1.进程状态切换PCB的作⽤状态变化时内核更新PCB中的state字段并保存/恢复寄存器值。生命周期发生什么PCB内容关键字段改变创建程序代码加载进内存PCB产生内核分配内存初始化数据分配PID就绪资源准备就绪等待CPUPCB被移入就绪队列就绪运行获得CPU指令执行PCB移出就绪队列CPU寄存器上下文被载入运行记录CPU时间阻塞等待I/OPCB移出CPU移入阻塞队列保存现场阻塞保存上下文信息唤醒I/O完成事件发生PCB从阻塞队列移入就绪队列等待上传CPU就绪终止进程结束若父进程未收回变成僵尸父进程wait回收后PCB销毁终止回收PID2.进程切换CPU快速切换我们以为在同时进行但是频繁切换会降低性能本质1.保存当前进程的PCB2.加载下一个进程的PCB到CPU6.组织进程内核中所有的task _struct通过tasks字段struct list_head连接成一个双向循环链表优势1.高遍历所有进程2.动态增删只需要修改指针7.查看进程通过 /proc系统文件夹查看例如获取PID为1的进程信息需要查看/proc/1这个文件夹⼤多数进程信息同样可以使⽤top和ps这些⽤⼾级⼯具来获取ps -aux 文件名8.通过系统调用获取进程标识符进程 进程idPID 父进程idPPID)系统调用getpid getppid关键点•PID是唯⼀的操作系统通过PID区分不同进程。•⽗进程⼤多数进程由shell或其他进程创建类似“⽗⼦关系”。9.通过系统调用创建进程-forkfork()复制当前进程创建⼀个⼦进程。调⽤⼀次返回两次⽗进程⼏乎原封不动地克隆出⼀个⼦进程。核心特性fork()让⼦进程继承家产内存、⽂件描述符但不继承⾝份PID/PPID、不继承历史CPU时间、挂起信号、不继承约束⽂件锁、定时器。⼦进程是⼀个全新的个体⼦进程获得⽗进程数据段、堆栈段的完整副本⽗进程和⼦进程拥有独⽴的地址空间任⼀进程的修改不会影响另⼀个进程进程在CPU时间统计10.程序替换-exec家族fork可以创建⼀个全新⼦进程但⼦进程默认执⾏和⽗进程⼀模⼀样的代码。很多场景我们希望⼦进程去运⾏⼀个完全不同的外部程序1.execve系统调用功能替换当前进程的代码段、数据段、堆、栈执⾏⼀个新程序。execve是唯⼀真正的系统调⽤execl/execlp/execv/execvp/execle均为glibc库函数特点•成功不返回当前进程被替换•失败返回-1注意①exec不改变进程PID②⽂件描述符继承规则exec执⾏时默认已经打开的⽂件描述符会继承到新程序只有设置了FD_CLOEXEC标志位的fd执⾏exec时⾃动关闭。③信号处理继承规则exec替换程序之后1.⽤⼾⾃定义的信号处理函数全部重置为系统默认⾏为2.信号阻塞掩码会保留不变2.execl/execlp/execv/execvp对⽐四个常⽤库函数的区别命名规则•llist参数以可变参数列表逐个传⼊末尾必须填NULL•vvector参数放到字符串数组中统⼀传⼊数组末尾必须是NULL•ppath会⾃动读取PATH环境变量搜索可执⾏⽂件只需写程序⽂件名不⽤写完整路径注意1.列表形式l参数⼀个个写最后强制NULL结尾2.数组形式 v适合参数数量动态变化的场景3.带p不⽤写绝对路径不带p必须提供可执⾏⽂件完整路径。3.exec函数对比总结l列表 v数组 p找路径 e环境二 进程状态•CPU数量有限通常只有⼏个但进程数量可能成百上千•操作系统需要⼀种⽅式来跟踪每个进程当前在做什么•根据进程状态操作系统决定如何分配CPU资源1.进程状态机就绪等CPU运⾏占CPU阻塞等I/O。调度算法决定谁上谁下。就绪与阻塞就绪态是可运⾏但未分配CPU阻塞态是因资源不可⽤⽆法运⾏⼆者区分提⾼了调度效率。进程状态查看1. ps axu 查看所有进程状态 STAT列2. ps ef3. top 动态查看进程状态和内存4.ps aux | grep 文件STAT列含义◦R运⾏或就绪◦S可中断休眠等待事件◦D不可中断休眠通常等待I/O◦Z僵⼫进程◦T暂停状态如CtrlZ挂起◦I空闲状态2.僵尸进程定义⼦进程终⽌后⽗进程未调⽤wait()或waitpid()回收其资源导致内核保留⼦进程的退出状态PCB残留关键特点◦进程已死亡但仍占⽤**进程ID**PID和少量内核资源。◦⽆法⽤kill命令杀死因其已终⽌。查看⽅式危害1.⽗进程不断创建⼦进程⼦进程退出后变成僵⼫⽗进程不回收僵⼫越积越多2.PID号被⼤量僵⼫进程占⽤有限通常最⼤值32768或更⼤如/proc/sys/kernel/pid_max3.系统⽆法分配新PID→新进程创建失败4.PCB进程控制块占⽤内核内存解决◦⽗进程调⽤wait()或waitpid()主动回收。◦若⽗进程不处理可终⽌⽗进程僵⼫进程会被init接管并清理。3.进程等待 -wait/waitpid用处1.回收⼦进程资源避免僵⼫进程2.获取⼦进程的退出状态正常退出码or被信号终⽌wait函数功能阻塞等待任意⼀个⼦进程结束回收其资源。参数status传出参数⽤于获取⼦进程的退出状态。如果不需要可传NULL。waitpid函数功能等待指定⼦进程结束可设置⾮阻塞模式。参数返回值含义0退出的子进程PID0⾮阻塞模式下没有⼦进程退出-1出错status获取退出状态wait与waitpid对比wait和waitpid是回收⼦进程、避免僵⼫进程的核⼼函数。wait简单但功能有限waitpid更灵活⽀持⾮阻塞和指定⼦进程。pid_t说明pid_t是Linux系统专⻔为进程ID定义的类型别名typedef本质底层就是int凡是和进程ID相关的返回值、变量统⼀使⽤pid_t类型简单总结pid_t返回值告诉你“哪个⼦进程死了”status变量告诉你“⼦进程怎么死的、退出码是多少”4.孤儿进程定义⽗进程先于⼦进程终⽌⼦进程被init/systemd进程⾃动接管。•关键特点◦孤⼉进程仍在正常运⾏⽆危害◦init进程会定期调⽤wait()清理其终⽌后的资源孤儿进程与僵尸进程三 进程优先级在多任务系统中CPU资源有限操作系统需要决定哪个进程优先获得CPU时间。优先级⾼的进程会被调度器更频繁地执⾏。例如后台下载任务低优先级vs ⽤⼾交互程序⾼优先级。1.查看系统进程用ps -AI命令我们收到信息之后可以看到UID:代表执⾏者的⾝份PID:这个进程的代号PPID⽗进程的代号PRI代表这个进程可被执⾏的优先级其值越⼩越早被执⾏NI代表这个进程的nice值其表⽰进程可被执⾏的优先级的修正数值表⽰⼀个进程愿意让出CPU的程度nice值越大越友善-20⾄19调整进程优先级在Linux下就是调整进程nice值查看nice值ps -eo pid,ni,comm,args | head -10PRI与NI