目录
一、进程状态基本概念
(一)什么是进程状态
- 就是PCB中的一个字段,就是PCB中的一个变量,int status
typedef struct {
// 其他成员...
int status; // 假设你有一个状态字段来表示 PCB 的状态
} PCB;
// 定义状态常量
#define NEW 1
#define RUNNING 2
#define BLOCK 3
- 老版Linux内核源码中的:
// 这里定义了进程运行可能处的状态。
#define TASK_RUNNING 0 // 进程正在运行或已准备就绪。
#define TASK_INTERRUPTIBLE 1 // 进程处于可中断等待状态。
#define TASK_UNINTERRUPTIBLE 2 // 进程处于不可中断等待状态,主要用于I/O 操作等待。
#define TASK_ZOMBIE 3 // 进程处于僵死状态,已经停止运行,但父进程还没发信号。
#define TASK_STOPPED 4 // 进程已停止。
(二)进程状态变化的本质
- 更改pcb status整型变量
- 将PCB连入不同的队列中
(三)运行队列和运行状态
- 每个CPU核心对应一个运行队列
- 将一个进程放入运行队列,本质上就是将对应的
task_struct
结构体对象加入到运行队列中(将task_struct
对象的state
字段设置为TASK_RUNNING
) -
当调度器选择了一个进程执行,它会从相应的运行队列中取出对应的
task_struct
结构体对象,并将其中的信息(寄存器状态、程序计数器(PC)的值等)加载到CPU中,CPU会根据加载的信息开始执行进程的指令,直到进程遇到一个需要等待的事件(例如等待I/O操作完成)或者时间片(时间片轮转调度)用完 - 在CPU的运行队列中,进程的状态通常被称为运行状态
(四)阻塞状态
- pcb没有在运行队列中,并且状态不是running
(五)挂起
- 如果系统内的资源(如内存)严重不足,内核可能会决定将某些进程从内存中移动到磁盘上,以释放物理内存。这被称为挂起进程,也称为进程换出
- 一个进程当前被阻塞了,那么在它等待的资源没有就绪的时候,该进程无法被调度的,如果此时,恰好OS内的内存资源已经严重不足了,将内存数据移动到磁盘上,称为阻塞挂起
- swap分区,OS中的数据会被交换到这里
- 当进程被OS调度,曾被置换出去的进程的数据和代码,又要重新加载回来
二、Linux操作系统的进程状态
(一)Linux内核源代码----进程状态
static const char *task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"T (tracing stop)", /* 8 */ //进程被调试器暂停
"Z (zombie)", /* 16 */ //僵尸进程,它已经结束执行,但其父进程还未对其进行善后处理
"X (dead)" /* 32 */ //进程已经结束执行
};
(二)各种状态
1. 浅度睡眠状态-S(阻塞状态的一种)
- S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep)),浅度睡眠状态是可以被终止的进程状态
- 状态后面有+号的表示前台进程,没有+号表示后台进程
- 前台进程可以通过ctr+c结束,后台进程通过kill -9 PID终止进程
while :;do ps ajx | head -1 && ps ajx | grep mybin |grep -v "grep";sleep 1;echo "#————————————————————————————————————————————————————#";done
grep -v "grep"
:这个部分会排除掉包含 "grep" 字符串的行,以避免显示出grep命令本身
#include<stdio.h>
#include<unistd.h>
int main()
{
while(1)
{
printf("hello,world\n");
sleep(1);
}
return 0;
}
2. 深度睡眠状态-D
- D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep)。进程处于深度睡眠状态通常意味着它在等待一个耗时的I/O(输入/输出)操作完成,例如从硬盘读取数据。
- 在这种状态下,进程对于普通的信号来说是不响应的,也就是说即使是系统管理员或操作系统本身也不能轻易终止这个进程。只有等待相应的I/O操作完成,进程才会自动恢复。
3. R运行状态
- R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里
#include<stdio.h>
#include<unistd.h>
int main()
{
while(1)
{
}
return 0;
}
4. T停止状态
- T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
- 为什么要将进程暂停?在进程访问软件资源的时候,可以暂时不让进程访问,就将进程设置为STOP
kill -SIGSTOP 18262//将进程号为18262的进程暂停
kill -SIGCONT 18262//让进程号为18262的进程从暂停状态中恢复,继续执行
5. t (tracing stop)
- dubug程序的时候,追踪程序,遇到断点,进程暂停了
三、僵尸状态-Z
(一)定义
- 当一个进程退出时,退出信息会由操作系统写入到当前退出进程的PCB中,可以允许进程的代码和数据空间被释放,但是不允许进程的PCB被立即释放。进程退出,但是还没有被父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时,操作系统必须维护这个退出进程的PCB结构-----状态:僵尸状态(Zombies)
- 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
- 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
(二)僵尸进程危害
- 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!
- 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护?是的!
- 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!
(三)创建维持僵死进程例子
四、孤儿进程
- 父进程先退出,子进程就称之为“孤儿进程”
#include<stdio.h>
#include<unistd.h>
#include <stdlib.h>//exit的头文件
int main()
{
pid_t id = fork();
if(id < 0)//创建进程失败
{
return 1;
}
else if(id == 0)
{
while(1)
{
printf("I am a child....\n");
sleep(1);
}
}
else{//父进程
int count = 5;
while(count)
{
printf("I am a father, run times: %d\n",count--);
sleep(1);
}
printf("I am a father, dead!: %d\n",count--);
exit(1);
}
return 0;
}
- 前台创建父进程和子进程,父进程被杀掉后,父进程立马被bash回收
- 父进程先结束后,子进程被1号进程领养,而 1 是系统中的 init 进程的进程 ID。init 进程是系统启动时的第一个进程,它负责启动和管理所有其他进程。
- 如果没有被领养,它可能会变成僵尸进程(zombie process)。僵尸进程是已经退出但仍然在进程表中保留条目的进程,这可能会导致内存泄露。
五、进程优先级
(一)基本概念
- cpu资源分配的先后顺序,就是指进程的优先权(priority)。
- 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
- 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能
- 优先级本质就是PCB中的一个int字段,数值越小,优先级越大
(二)查看系统进程
ps -la //以详细的格式显示所有运行中的进程,包括所有用户的进程
- UID : 代表执行者的身份
- PID : 代表这个进程的代号
- PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
- PRI :代表这个进程可被执行的优先级,其值越小越早被执行
- NI :代表这个进程的nice值,表示进程可被执行的优先级的修正数值
- PRI(新)=PRI(旧)+nice
- 调整进程优先级,在Linux下,就是调整进程nice值
- nice其取值范围是-20至19,一共40个级别
(三)用top命令更改已存在进程的nice
- top
- 进入top后按“r”–>输入进程PID–>输入nice值