前言
作者:小蜗牛向前冲
名言:我可以接受失败,但我不能接受放弃
如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正。
目录
本期学习目标:理解操作系统下进程状态,Linunx下进程状态,认识僵尸进程和孤儿进程及进程的优先级和进程切换。
在学习进程状态的之前,我们先简单复习一下,什么是进程:进程其实就相当于进程控制模块(pcb)加上磁盘上的可执行程序。
对于一个操作系统来说,他其实会有非常多种状态,但是最常见的还是就绪、执行、阻塞。
- 就绪:当进程已经分配好除CPU外的所以资源,只要再获取CPU后就能够马上运行。
- 执行:进程已经获得CPU,其程序正在被执行
- 阻塞:正在执行的进程由于发生某事件而暂时无法继续执行时,便放弃CPU而处于暂停状态,亦即进程的执行受到阻塞,把这种暂停状态称为阻塞状态,有时也称为等待状态或封锁状态。比如进程当中调用wait()函数,会使得进程进入到阻塞状态。
但是为了满足一些操作系统的需求,就又出现了一些其他的状态:挂起状态、创建状态、终止状态。
对于挂起状态他是一种特殊的请求,下面简单聊聊为什么要有挂起状态:
(1) 终端用户的请求。当终端用户在自己的程序运行期间发现有可疑问题时,希望暂时使自己的程序静止下来。
(2) 父进程请求。有时父进程希望挂起自己的某个子进程,以便考查和修改该子进程,或者协调各子进程间的活动。
(3) 负荷调节的需要。当实时系统中的工作负荷较重,已可能影响到对实时任务的控制时,可由系统把一些不重要的进程挂起,以保证系统能正常运行。
(4) 操作系统的需要。操作系统有时希望挂起某些进程,以便检查运行中的资源使用情况或进行记账
而对于其他的二种状态:
- 创建状态:为一个新进程创建PCB(进程控制块,它是系统为了管理进程设置的一个专门的数据结构,主要表示进程的状态),把该进程转入到就绪状态并插入到就绪队列之中。
- 终止状态:等待操作系统进行善后处理,然后将其PCB清零,并将PCB空间返还系统
前面我们说的哪些状态是所以操作系统进程状态的统称,下面我们来看看Linux这些状态是如何体现的;为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态(在 Linux内核里,进程有时候也叫做任务)。 下面的状态在kernel源代码里定义:
- /*
- * The task state array is a strange "bitmap" of
- * reasons to sleep. Thus "running" is zero, and
- * you can test for combinations of others with
- * simple bit tests.
- */
- 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运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里
- S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
- D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的 进程通常会等待IO的结束。
- T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可 以通过发送 SIGCONT 信号让进程继续运行。
- X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
进程状态查看:
ps ajx | head -1 && ps ajx | grep 'test'
由于在test.c文件中我们是用fork创建子进程的,也就是说在fork函数运行前只有父进程,而运行后就既有子进程也有父进程。我们知道如果进程创建成功,就将0返回回给子进程,将子进程的pid返回给父进程。这里我们就只打印出子进程,并休眠2秒。
这里我们观察到父进程一直在运行,而子进程反而处于休眠状态,这是为什么呢?
其实父子进程都在运行的,由于父进程不需要打印到屏幕中,也将不用调用外设资源。所以就处于运行状态,而子进程要打印到屏幕上,所以要调用外设资源,而CPU的运行速度是远大于外设的,所以cpu就会将子进程移除运行队列进行等待,子进程就进行休眠状态了。
这里我们要注意状态的上的+号,表示进程前台,这式我们在进程在跑的时候,输入指令是没有用的但是可以按ctrl+c强制将进程终止,但是如果我们把进程kill -9(杀死后在运行),+号就会消失,我们也就变成了前台进程,这时候输入指令都是有用处的,但是我们就不能按ctrl+c让进程强制终止。
- //暂停进程
- kill -19 进程的pid
- //进程继续
- kill -18 进程的pid
-
-
下面我们继续来见一见进程的暂停和启动
那我们能见见死亡进程吗?
- //杀死进程
- kill -9 进程的pid
我们可以看到这里怎么没有子进程的状态变成X状态,反而变成了Z状态,这又是个什么状态呢?
其实这是是僵尸状态,下面我们一起来看看僵尸状态吧
改进程听起来好奇怪,其实他就是当子进程退出了,而父进程没退出,父进程要接受子进程的各种信息时,子进程存在的一种状态,已经死去了但是基本信息海存在等这父进程用wait()接受。
这里的test虽然被杀死了,但是我们在进程查看中还是能看到他的运行状态。
僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲) 没有读取到子进程退出的返回代码时就会产生僵死(尸)进程 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。
僵尸进程危害
- 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎 么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!
- 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话 说,Z状态一直不退出,PCB一直都要维护?是的!
- 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构 对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!就会存在内存泄漏
上面我们说到子进程退出,还有父进程可以回收子进程的信息,子进程只要维持僵尸状态等父进程来回收就可以了,但是如果父进程先退出了,那子进程退出后处于Z状态又该谁来回收呢?
有的,子进程这时候会被1号init进程(os)领养,在由1号init进程回收。
- cpu资源分配的先后顺序,就是指进程的优先权(priority)。
- 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
- 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整 体性能
我们先输入这个命令认识一下进程优先级:
ps -l
- UID : 代表执行者的身份
- PID : 代表这个进程的代号
- PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
- PRI :代表这个进程可被执行的优先级,其值越小越早被执行
- NI :代表这个进程的nice值
这里我们要重点关注这二个标识,上面说了PRI他的值越小那么他进程的优先级就会越高,也就说他的进程会被CPU优先跑,而NI只要是可以影响PR从而影响进程的优先级。
总结:
- PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小 进程的优先级别越高。
- 那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值 PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice (这里的old都是从80开始)这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行 所以,调整进程优先级,在Linux下,就是调整进程nice值 nice其取值范围是-20至19,一共40个级别。
- 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进 程的优先级变化。 可以理解nice值是进程优先级的修正修正数据。
那么我们是通过什么来修改优先级的呢?
下面我们就用top命令来修改进程的nice:
当我们输入top + r +输入你要修改进程的pid回车后在输入你要修改nice的值是多少,但是我们输入-100时(这里的top要用sudo提权):
这里的nice最低就修改为-20,因为我们不可能一直提供进程的优先级,这也要是有一个限度的。
- 竟争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高 效完成任务,更合理竞争相关资源,便具有了优先级。
- 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
- 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
- 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为 并发。
这里我们重点来理解进程是怎么在CPU下进程切换的。
我们应该明白一个操作系统不可能就一个进程在跑,但是一CPU是只能一下完成一个工作的,那我们拿window操作系统来举例:我电脑上为什么既可以登QQ、微信、听歌,敲代码。这些我们都可认为是进程,难道这些进程都在跑吗?这显然不是的,那操作系统是如何做到呢?
这就要依靠进程切换了,一个CPU中不仅仅存在在PCB用来管理进程,还存在这大量可见和非可见的寄存器。那这些寄存器有什么用呢?进行对正在运行的进程,取指令、分析指令、执行指令(注意:寄存器中的数据是属于但前进程)。
假设操作系统现在有三给进程A,B,C都要跑,CPU会先根据这三个进程的进程优先级,决定那个进程先跑,假设A