【Linux复习】:进程概念

张开发
2026/6/9 21:19:55 15 分钟阅读
【Linux复习】:进程概念
进程概念冯诺依曼核心所有硬件都是围绕内存工作的,所有数据必须先加载到内存CPU 才能访问。外设:输入设备键盘、鼠标、硬盘负责把数据传给内存输出设备显示器、硬盘负责从内存拿数据内存临时数据中转站速度快、断电丢失CPU运算核心只和内存交互IO:输入 / 输出外设 ↔ 内存 的数据交互数据流:外设 → 内存 → CPU → 内存 → 外设存储分级与IO效率:寄存器 缓存 内存(瓶颈) 硬盘速度递减容量递增操作系统管理软硬件提供稳定安全的运行环境管理先描述用结构体如 task_struct把资源的属性写清楚再组织用链表 / 队列把所有结构体管理起来例子管理进程 → 先定义 PCB 结构体 → 用链表串起所有 PCB库函数与系统调用接口库函数内部是封装了系统调用接口的进程概念原因当程序运行时要从硬盘加载到内存当中操作系统为了更方便的管理每个程序的运行就要首先描述出每一个进程的相关信息所以有了进程控制块而Linux中的PCB就是task_struct描述信息内存mm_struct** 文件** files_struct(打开的文件存储在指针数组)struct file * file_arrays[]上下文数据CPU 寄存器数据进程切换时保存 / 恢复信号信号的阻塞位图sigset_t blocked信号的处理方法struct sigaction进程控制进程创建fork复制以父进程为模板为子进程创建PCB子进程和父进程共享代码和数据写时拷贝返回值父进程返回子进程的pid子进程返回0失败返回-1vfork共享同一个虚拟地址空间创建一个进程的流程找到父进程的PCB对象malloc一个PCB来存放子进程用父进程的PCB初始化子进程子进程的PCB指向父进程的代码和数据子进程和父进程都加入调度队列开始排队等待调度当有一方要改变数据时就会触发写时拷贝进程终止终止的几种情况正常终止结果正确代码正常执行完毕正确退出码是0正常终止结果不正确代码也正常执行结束了但是不在合适的地点退出退出码不为0异常代码没有正常执行结束可以使用**echo $?**来查看exit code当进程收到信号而退出后可以父进程可以通过回收资源收到退出码以查看子进程的退出情况终止的操作对比exit和_exit_exit是系统调用exit:_exit刷新缓冲区关闭文件main 的 returnreturn n 等价于 exit (n)其他return :进程还在跑进程终止系统的行为根据被终止进程的标识操作系统会从它的PCB集合中找到该进程的PCB读取该进程的状态2. 如果该进程处于执行状态会立即停止执行并修改状态标识表示这个进程被终止3.回收进程的资源4. 保留pcb等待父进程回收5.从运行队列中移除进程等待原因防止内存泄漏子进程退出父进程不回收(waitpid)就会导致僵尸状态的出现僵尸进程子进程异常终止父进程并没有调用wait/waitpid子进程的进程描述符等资源仍在系统中占用资源那么此时子进程就变成了僵尸进程Z进程等待的方式waitpid_t wait(int *status);waitpid pid_t waitpid(pid_t pid, int *status, int options);option为0表示阻塞等待WNOHANG表示非阻塞等待status是一个输出型参数0-7是退出信号8-15是位图signal(退出信号)和exit code(位图)阻塞等待和非阻塞等待阻塞等待是停在函数调用位置等待直到回收资源成功非阻塞等待是每到接口处就检测搭配循环使用可以做其他事进程状态创建就绪运行阻塞终止状态每一种状态就是宏定义状态变换本质就是修改宏的值放入不同的队列就绪状态当进程的时间片用完之后就会从CPU上剥离下来此时会保存寄存器的代码和数据存储到PCB当中紧接着把进程的PCB加入到就绪队列当中等待下一次调度运行挂起状态当进程在阻塞状态时如果内存资源不足会暂时把阻塞进程的代码和数据置换到磁盘的swap分区中当进程被调度的时候再把数据加载进来转换流程僵尸进程产生原因子进程终止父进程不回收子进程资源危害子进程的数据没有被回收就会内存泄漏避免进程等待主动调用接口waitpid进行阻塞或非阻塞等待SIGCHLD子进程结束后会向父进程发送一个信号父进程可以对于该信号进行自定义设置方案即可处理signal(SIGCHLD, SIG_IGN);父进程忽略 SIGCHLD内核就会自动回收子进程不再留僵尸父进程不用写任何 wait /waitpid孤儿进程产生原因子进程未终止父进程先终止了处理这是无害的bash(init 进程pid1)会领养孤儿进程由bash进程进行回收资源守护进程后台运行不接受任何终端的输入,关掉终端也不退出脱离控制自己创建一个会话成为会话组长进行管理自己独立生命周期用孤儿进程的方式由bash领养避免父进程影响总结连续2次fork进行变成孤儿进程再自己创建一个会话管理自己#include stdio.h #include stdlib.h #include unistd.h #include signal.h #include fcntl.h void daemonize() { // 1. 第一次 fork父进程退出 if (fork() ! 0) exit(0); // 2. 子进程创建新会话脱离终端 setsid(); // 3. 第二次 fork防止重新打开终端 if (fork() ! 0) exit(0); // 4. 忽略子进程退出信号避免僵尸 signal(SIGCHLD, SIG_IGN); // 5. 重定向标准输入输出到空设备 int fd open(/dev/null, O_RDWR); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); close(fd); } int main() { // 变成守护进程 daemonize(); // 后台死循环运行 while (1) { sleep(1); } return 0; }环境变量概念用来指定操作系统运行环境的一些参数指明动静态库的位置PATH指定命令的搜索途径HOME指定用户的主工作目录SHELL当前shell一般是bash相关命令echo $PATH – 查看环境变量export 变量名val --新增一个环境变量env 显示所有环境变量unset 变量名;清除环境变量set 显示所有变量包括本地变量 环境变量特性main函数参数的第三个参数int main(int argc, char* argv[], char* envp[])环境变量信息是以脚本配置文件形式存在的每次登陆从 ./bash_profile 当中读取内容创建表本地变量不能被子进程继承环境变量可以4.环境表本质上是一个字符指针数组,以NULL结尾命令常规命令fork子进程让子进程执行该命令内建命令shell命令行的函数直接读取环境变量代码中获取设置环境变量*getenv(const char name)获取环境变量**setenv(const char name, const char value, int overwrite)设置 / 修改环境变量*putenv(char string)传入 namevalue 格式字符串设置环境变量虚拟地址空间是什么就是操作系统内核里的一个结构体mm_struct为什么提高内存利用率不用一次性加载全部代码 / 数据按需分配、swap 换入换出解决内存碎片问题增加内存访问控制与安全不能直接访问物理内存通过页表权限控制只读、可读写、可执行越界访问会触发段错误保护内核和其他进程保证进程独立性每个进程都以为自己独占内存进程之间地址空间完全隔离一个进程崩溃不会影响其他进程怎么做分段式内存管理程序由若干个逻辑分段组成代码分段数据分段栈段堆段等不同的段有不同的属性用分段的形式可以把段分离开分页式内存管理产生连续的内存空间把整个虚拟地址和物理内存空间划分为固定尺寸的大小每一页是4KB通过页表映射虚拟页号 → 物理页号段页式内存管理先划分成逻辑意义的段也就是分段机制再把每一个段划分成多个固定大小的页由段号段内页号页内偏移定位信息进程替换是什么进程替换 把当前进程的代码和数据全部换掉换成另一个程序不创建新进程PID 不变只是换程序内容执行成功会发生什么用新程序的代码段、数据段覆盖当前进程原来的代码直接作废从新程序的 main 函数开始执行不会回到原来的程序成功没有返回值执行失败返回 -1继续执行原来的代码系统调用接口l → list参数以列表形式给出逐个写v → vector参数以数组形式给出p → path自动去 PATH 里找命令e → environment自己传环境变量逐个说明execl按列表传参需要写全路径execl(/usr/bin/ls, ls, -l, NULL);execlpp 自动找 PATH不用写全路径execlp(ls, ls, -l, NULL);execlee 自己传环境变量execle(ls, ls, -l, NULL, envp);execvv 用数组传参char* argv[] {ls, -l, NULL}; execv(/usr/bin/ls, argv);execvpv pchar* argv[] {ls, -l, NULL}; execvp(ls, argv);execvpev p eexecvpe(ls, argv, envp);MySQL shell连接数据库执行 SQL管理数据库mysql -uroot -p

更多文章