进程:本质为运行中的程序 程序:存储在硬盘中的可执行程序文件
操作系统如何管理进程?先描述,后组织 站在操作系统的角度来说,进程就是操作系统对进程的描述-->pcb(进程控制块) struct task_struct结构体 描述进程:标识符(PID),进程状态,优先级,内存指针,上下文数据, 程序计数器,io状态信息,记账信息(cpu上运行时间) 进程的切换调度:cpu的分时技术---时间片 查看进程:ls /proc/ ps -ef aux top(显示前几个) getpid函数(进程ID) 进程的创建: fork() 操作系统提供创建进程的接口fork通过复制父进程的pcd,意味着子进程跟父进程代码和数据指向的是同一块内存区域(数据跟代码运行的完全一样),并且子进程拷贝了程序计数器,上下文数据,所以当前的子进程是从子进程创建成功的下一步指令开始运行的.
父子进程代码共享,数据独有 为什么创建子进程:分摊压力,运行其他任务 如何分辨子进程:父子进程的返回值不同 返回值:在父进程中,返回子进程id(pid>0);在子进程中返回0 我们用户就是通过返回值对父子进程进行代码分流 进程状态:阻塞、运行、就绪 linux下的进程状态: 运行 R 可中断睡眠 S 不可中断睡眠 D 停止 T 僵尸 Z 追踪 X 僵尸进程:处于僵死状态的进程 危害:资源泄漏 产生:子进程先于父进程退出,操作系统通知父进程,但是父进程没有管,操作系统不敢 擅自释放子进程所有资源,一旦释放就没有地方保存退出原因,因此子进程就成了僵尸进程 。操作系统不释放的原因是:子进程退出原因保存在pcb中。 处理:退出父进程 预防:进程等待 孤儿进程:父进程先于子进程退出,孤儿进程的父进程变为1号进程init进程,并且孤儿进程退出 不会产生僵尸进程 守护进程/精灵进程:特殊的孤儿进程 进程优先级:数字 功能:决定cpu资源的优先分配权 查看:ps -l PRI NI 优先级无法直接修改,但是可以通过设置NI的值而对优先级进行设置 nice值的取值范围[-20~19] PRI = PRI + NI 优先级的修改方法: nice -n ni_val ./main renice -n ni_val -p pid 进程的相关概念:竞争性:进程之间对于资源具有竞争性 独立性:进程之间应该相互独立 并行:进程同时在cpu上运行 并发:进程切换在cpu上运行 环境变量:用于存储操作系统运行环境参数的变量->操作系统运行配置更加方便 查看:env set echo(指定$环境变量名称) 声明:export 删除:unset 作用:让程序运行更加高效,因为环境变量具有全局特性 如何在代码中获取环境变量:getenv() main的第三个参数 全局变量char** environ 程序地址空间: 虚拟地址空间(mm_struct结构体)这个结构体是进程对内存的描述(内存描述符) 为什么要用虚拟地址空间? 提高内存利用率,增加内存访问控制;保证进程的独立性 程序地址空间:每一个程序都有自己的程序地址空间 内存地址:内存区域的编号 进程地址空间:代码共享,数据独有 写时拷贝技术 我们所说的程序地址空间,实际上是一个进程的虚拟地址空间,目的是为了告诉进程, 每个进程都有一个完整连续的内存,但是真正一个进程使用的内存经过页表映射后可能只 使用了很少一部分物理内存。 使用页表虚拟地址空间,记录映射关系,内存访问控制。 页表:记录虚拟内存与物理地址的映射关系,并且对内存进行访问控制 分页式内存管理:提高内存利用率 进程调度:cpu调度进程其实调度的是pcb 大O(1)调度算法:用空间换时间 有多少优先级就使用多少队列,用位图记录各个优先级队列中是否有进程, 调度完成后,有同样的队列记录过期的进程全部调度完毕后,交换指针,新的队列 就变为旧的,旧的变为新的队列。模拟实现孤儿进程和僵尸进程
// 模拟实现僵尸进程 #include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { pid_t pid; pid = fork(); if(pid < 0) { perror("fork error:"); exit(1); } else if(pid == 0) { sleep(1); printf("child exit!\n"); } else { while(1) { printf("I am busy!\n"); sleep(3); } } return 0; }僵尸进程的形成原因就是子进程先于父进程退出,操作系统告诉父进程查看退出原因(退出原因保存在pcb中),但是父进程正在做其他事情,来不及去处理,操作系统不能擅自释放,子进程就形成了僵尸进程。 僵尸进程的主要危害就是造成资源浪费,其实僵尸进程的大部分资源已经被操作系统释放,但是僵尸进程内核(pcb)中的资源不能释放,所以就造成了资源泄露。
// 模拟实现孤儿进程 #include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { pid_t pid; pid = fork(); if(pid < 0) { perror("fork error:"); exit(1); } else if(pid == 0) { while(1) { printf("I am child, my parent is %d\n", getppid()); sleep(2); } } else { sleep(1); printf("I am parent, exit\n"); } return 0; }孤儿进程的产生原因是父进程先于子进程退出,子进程的父进程自动变为1号init进程,孤儿进程不会产生僵尸进程,可以理解为孤儿进程只是换了一个父进程。