目录
一、操作系统的进程状态
1.1运行状态
1.2阻塞状态
1.3挂起
二、Linux下具体的状态
三、进程的优先级
3.1基本概念
3.2查看进程优先级的命令
3.3修改进程优先级的命令
3.4其他概念
3.5并发
一、操作系统的进程状态
1.1运行状态
- 当一个进程准备就绪,获得了CPU资源,就会在CPU所维护的运行队列上等待CPU的调度
- 一个进程在运行或者处于运行队列中,都叫做运行状态
- 一个进程并不是一直在CPU上执行的,而是会以进程切换的方式,在一段时间内,使多个进程同时被推进---并发
- CPU对进程的调度是基于进程切换和时间片轮转的调度算法
1.2阻塞状态
-
当一个进程正在等待某种IO事件的完成,实际上就是在等待获取某种资源,那么该进程就处于一种阻塞状态
-
操作系统对软硬件资源进行管理,都要遵循“先描述再组织”的原则,操作系统对外设的管理就是在内存中创建一个个的外设数据结构对象,再用链表的方式组织起来
-
每一个外设的pcb数据结构对象都会包含一个等待队列,当一个进程在获取某种外设资源时(比如scanf),外设资源还未准备好,该进程就会链入该外设的pcb等待队列进行等待,此时进程就处于阻塞状态,直到资源准备就绪,才会被链入运行队列等待CPU调度,将状态S改为R
1.3挂起
- 当进程在队列中排队,操作系统的资源严重不足或者操作系统需要给新加入的进程提供空间,那么此时操作系统就会将正在等待排队的进程所对应的数据和代码换出到外设分区中,等到该进程被调度了再换入给该进程
- 从换出到换出的过程,进程处于挂起状态
二、Linux下具体的状态
static const char * const task_state_array[] ={"R (running)", /* 0 */"S (sleeping)", /* 1 */"D (disk sleep)", /* 2 */"T (stopped)", /* 4 */"t (tracing stop)", /* 8 */"X (dead)", /* 16 */"Z (zombie)", /* 32 */};
- R就是操作系统中进程的运行状态:并不意味着该进程一定在运行中,它表明该进程要么在运行要么在运行队列中
- S和D状态都对应操作系统中的阻塞状态:S是一种浅度睡眠,可以被唤醒;D是一种深度睡眠,不会响应任何请求
- 当一个进程正在进行某种IO事件,比如在向磁盘写入重要数据的时候,它必须等待磁盘写入完毕将写入结果反馈给进程,再反馈给上层用户,但如果这时候操作系统的资源严重不足,进程挂起已经没办法解决问题了,操作系统就会选择杀掉进程,如果一个进程在等待磁盘写入完毕的期间被杀掉,那么就会导致数据的丢失!为了防止这种情况,必须给该进程一个标识符--D,告诉操作系统我这个进程在等待磁盘写入完毕的期间是不能被杀掉的
- T停止状态:可以通过发送SIGSTOP来停止进程,可以发送SIGCONT来让进程继续运行,当一个进程想要获取某种资源或者被其他进程控制(如gdb),就可能会出现T状态
- X死亡状态:这个状态只是一个标识符,很难在任务列表里看见
- Z僵尸状态:当一个子进程退出的时候,它在内存中的pcb数据结构对象并没有立马被释放,这是因为子进程需要保留自己的退出信息让父进程读取,如果父进程一直不主动回收子进程的退出信息,子进程就会一直处于Z状态,僵尸进程会导致该进程的pcb数据结构对象无法被释放,进而导致内存泄露(子进程退出,父进程还没退出)
子进程退出,父进程没有退出并且没有回收子进程的退出信息,就会使子进程进入僵尸进程
- 孤儿进程:当子进程还没退出,父进程就已经推出了,那么该子进程就会被1号进程(操作系统)领养,此时的子进程就叫做孤儿进程。为什么要被1号进程领养?----为了让子进程在退出的时候可以被回收退出信息。此时退出进程不能再用Ctrl C 而应该使用kill -9 杀掉进程
三、进程的优先级
3.1基本概念
- CPU的资源是有限的,但是进程是多个的,这就注定了进程之间存在竞争关系
- 为了保证进程被CPU调度的公平和良性竞争,就必须引入进程优先级的概念
- 进程优先级是指CPU分配资源的先后顺序(访问资源的先后顺序)
- 如果一个进程长时间无法访问到资源,代码无法被推进,就会导致该进程的饥饿问题
-
优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可能改善系统性能
-
还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整 体性能
3.2查看进程优先级的命令
- 使用 ps -al
UID : 代表执行者的身份PID : 代表这个进程的代号PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号PRI :代表这个进程可被执行的优先级,其值越小越早被执行NI :代表这个进程的 nice 值
- PRI即进程的优先级,通俗点说就是程序被CPU执行的先后顺序,此值越小
进程的优先级别越高(默认80)
-
NI就是nice值,其表示进程可被执行的优先级的修正数值
-
PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行
-
所以,调整进程优先级,在Linux下,就是调整进程nice值 ,Linux为了保证优先级的调整范围,nice其取值范围是-20至19,一共40个级别
3.3修改进程优先级的命令
-
使用top r + 进程pid + 修正的nice值
- 操作系统是如何根据优先级展开调度的呢?:CPU会维护一个runqueue,runqueue中有两个调度队列,他们本质上是两个指针数组,存储40个优先级所一一对应的40个队列的指针,再结合位图的思想(调度完毕的队列为0,未调度完毕的队列为1),针对不同的优先级对进程进行调度!新加入的进程或者被进程切换下来的进程会链接到另外一个调度队列的对应的优先级的队列当中去,直到前一个调度队列全部调度完后,swap交换两个队列的指针,对另外一个未调度的队列进行调度,以此循环往复,也叫Linux内核的O(1)调度算法
3.4其他概念
- 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
- 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰
- 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行
- 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发
3.5并发
-
函数的返回值是如何被外部拿到的?----通过CPU寄存器
-
系统如何得知我们当前进程执行到哪一行代码?----通过pc(eip)程序计数器,记录当前进程执行的指令的下一条指令的地址
-
CPU中的寄存器很多!将进程中的高频数据放入到CPU的寄存器中可以提高效率
-
问题是,我们在进行进程切换到时候,如果不把属于当前进程的存储在寄存器中的数据带走,那么下一个来的进程在把数据放入寄存器的时候就会将上一个进程的数据覆盖,等到该进程重新被CPU调度,就无法从上一次执行的位置继续往下执行
-
CPU的寄存器中保存的是进程的临时数据,也叫进程的上下文
-
一个进程在被CPU高频调度的时候,必须经历调度----排队,在这个过程中,进程离开CPU必须自己保存上下文带走,再被调度时恢复上下文
-
总之,进程切换涉及到保存上下文和恢复上下文,寄存器中的数据在被保存时实际上是以结构体的形式被保存在内存中,进程的pcb数据结构对象中存在一个指向该结构体的指针