
学习资料https://pan.baidu.com/s/1NZpC4NyH0OHGOPPbO9J10g?pwdh9m2 提取码: h9m2一. 进程基础1.1 进程基本概念1. 程序 vs 进程程序是静态的指令集合不占用系统运行资源。进程是程序在系统中的一次动态执行过程占用系统资源CPU、内存、文件等一个程序运行多次会产生多个进程。2. Linux 进程的三种类型交互进程由 Shell 启动可在前台可与用户交互或后台加运行运行。批处理进程与终端无直接联系是一个按指定方式执行的进程序列。守护进程Linux 启动时运行的后台服务屏幕不显示任何信息在后台默默为用户服务如各类网络服务。3. 执行模式与 Shell进程在用户模式用户空间下运行当发生系统调用或中断时切换为内核模式核心程序运行具有特权指令不受用户干预。用户登录后打开的终端会建立一个Shell 进程接收用户命令并创建子进程执行进程结束后返回当前 Shell 继续接收新命令。1.2 进程创建和命令执行1.fork()系统调用 —— 创建子进程头文件#include unistd.h函数原型pid_t result fork(void);核心机制返回两次父进程返回新创建子进程的PID0。子进程返回0。出错返回-1。内核完成的工作① 为子进程分配新内存块和内核数据结构② 复制父进程信息代码段、数据段等二者拥有相同可执行代码③ 将新进程加入运行进程集合④ 执行完毕控制权返回给两个进程由调度器决定执行顺序。关键特性数据独立性fork之后父子进程的全局变量和局部变量虽然名称和初始值相同但它们在物理内存中是相互独立的互不影响。示例分析父进程执行glob变为11子进程执行local--变为7两者输出互不干扰。2.exec系列调用 —— 执行新程序当父进程希望子进程执行特定任务时会使用exec家族函数用新程序的指令代码替换子进程原有的代码段、数据段和堆栈相当于给子进程“换脑”。函数分类execl/execv要求提供可执行文件的绝对或相对路径。execlp/execvp使用PATH环境变量查找可执行文件p代表 PATH。传参方式llist逐个列举参数vvector使用字符串数组指针数组传递参数。执行流程将指定程序复制到调用它的进程 → 将字符串数组作为argv[]传递 → 运行新程序。核心特性exec成功调用后不返回任何值子进程原有的后续代码如printf将被新程序替换而不再执行但如果exec调用失败返回 -1子进程会继续执行后续代码。二. 进程退出进程退出主要分为正常退出和异常退出两类。1. 正常退出的 3 种方式程序正常运行结束进程自动消失。程序调用exit()函数退出。程序调用_exit()退出。2.exit()与_exit()的核心区别图 5.3exit()属于库函数。会先刷新缓冲区中的所有流调用用户通过atexit和on_exit注册的函数执行完其他与退出相关的操作后最后才调用_exit()。_exit()属于系统调用。会直接终止进程不刷新缓冲区也不执行用户注册的清理函数。3. 异常退出进程在运行时收到系统传来的外部信号而终止执行。例如kill -9 pid就是向进程号为 pid 的进程发送强制结束信号。2.1 守护进程Daemon1. 概念守护进程是脱离终端且在后台运行的进程。它不受终端控制即使终端退出它依然在后台运行如ftpd、crond、httpd。系统引导时会开启很多这种服务为用户提供功能。2. 核心概念进程组与会话期图 5.4进程组一组进程的集合由进程组 PID 表示。每个进程除了进程 ID 外还必须属于某个进程组。通常一个终端就是进程组组长。会话期由一个或多个进程组组成的集合。一个会话期开始于用户登录结束于用户退出。3. 创建守护进程的 5 个步骤图 5.5 例 5-5①创建子进程父进程退出调用fork()创建子进程然后让父进程exit()。这样子进程就变成了孤儿进程被系统的 init 进程PID 1收养从而脱离原终端的控制。②让子进程脱离控制终端在子进程中调用setsid()系统调用见表 5.3。它会创建一个新的会话并让调用它的进程成为该会话的组长。作用是让进程摆脱原会话、原进程组、原控制终端的控制。③改变当前目录为根目录子进程执行chdir(/)。防止当前目录如某个挂载点因为守护进程的存在而无法被卸载。④修改文件权限掩码调用umask(0)。将文件权限掩码设置为 0即取消子进程对文件操作的屏蔽限制增强守护进程的灵活性。⑤关闭文件描述符关闭从父进程继承的已打开的文件描述符。因为守护进程已与控制终端失去联系标准输入输出0、1、2等文件描述符不再被使用且会耗费系统资源应使用close(fd)关闭。2.2 僵尸进程Zombie1. 产生原因当子进程先于父进程结束而父进程没有使用wait()系统调用获取子进程的结束状态时子进程就会变成僵尸进程。注意如果是父进程先结束则不会产生僵尸进程。2. 特点与危害僵尸进程没有任何代码、数据或堆栈占用资源极少但它依然存在于系统的任务列表中进程表中占据一个位置。如果大量产生会耗尽系统的进程表资源。识别方法使用ps命令查看时如果进程名称旁边出现defunct则表明该进程为僵尸进程例 5-6 演示了如何通过让父进程长时间睡眠来观察僵尸进程。2.3 进程退出状态与等待为了防止子进程变成僵尸进程父进程需要调用wait()或waitpid()来等待子进程结束并获取其状态。1.wait()系统调用表 5.4头文件#include sys/wait.h、#include sys/types.h原型pid_t pid wait(int *status);功能暂停调用它的进程父进程直到有子进程结束。返回值如果不存在子进程返回 -1若有任何一个子进程结束则返回该子进程的 PID 并保存其返回状态在status中。2.waitpid()系统调用表 5.5与wait()的区别wait()的局限性只能等待任意一个子进程结束。当一个父进程有多个子进程时若某个子进程结束wait只能得到其结束状态无法再得到其他子进程的状态容易导致其他子进程变成僵尸进程。waitpid()的改进提供了非阻塞调用方式通过设置Options选项如WNOHANG如果没有已结束的子进程则马上返回不等待。可以等待指定的子进程通过传入特定的pid参数如pid 0等待指定 ID 的子进程pid 0等待同组任意子进程等。status参数用于保存返回状态options参数用于控制等待行为。3. 退出状态检测宏表 5.6系统提供了专门的宏来检测status变量判断子进程的退出情况WIFEXITED(status)如果子进程正常结束则此宏为真此时可调用WEXITSTATUS(status)取得子进程exit()返回的结束代码。WIFSIGNALED(status)如果子进程是因为信号而结束则此宏为真此时可调用WTERMSIG(status)取得导致子进程终止的信号代码。WIFSTOPPED(status)如果子进程处于暂停执行情况如收到 SIGSTOP则此宏为真此时可调用WSTOPSIG(status)取得引发子进程暂停的信号代码。