进程:本质为运行中的程序
程序:存储在硬盘中的可执行程序文件
操作系统如何管理进程?先描述,后组织
站在操作系统的角度来说,进程就是操作系统对进程的描述-->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进程,孤儿进程不会产生僵尸进程,可以理解为孤儿进程只是换了一个父进程。