1、进程状态
进程运行的时候会有很多个状态,它并不是简单地一个运行状态,也并不是一直运行。进程与进程之间存在切换,取决于系统让这个进程处于什么状态。了解具体状态之前,先了解阻塞和挂起。对于每一个进程,属于它的结构体在系统内部命名为task_struct。
1、阻塞
进程因为等待某种条件就绪而导致的一种不推进的状态。
一个进程被系统调度,被系统使用它的代码,这在用户的角度看来是运行的,如果有了代码但是系统不调度,那么用户角度来看,这个进程就是卡住了。比如运行多个程序时;同时下载好几个程序时,电脑一定为出现卡,这是因为有些进程没有被调度,才会出现卡顿,而进程卡住一定是在等待某种资源,比如下载程序就是在等待网盘资源,等待cpu资源,如果系统发现某个进程优先级更高,另一个进程需要等一下,那就让这个进程停住,进入阻塞状态,等优先级高的进程结束后才轮到它,这也就出现了卡顿。网卡资源的等待包括网断了这种情况。
现实生活中存在排队等待的情况,那么系统里对于进程等待这个情况是如何展现的?系统是管理软硬件资源的,系统可以通过自己描述好的方式来访问每个软硬件。对于进程,系统也是先描述再组织,描述成一个个结构体,通过数据结构来连接,比如链表。cpu不再调度一个进程后,进程变成阻塞状态,然后这个进程的pcb就会找到资源的结构,找到需要的资源的位置,然后连接在这个位置后面,等待得到足够的资源后,就又回到cpu那里让cpu调度。进程的pcb可以被维护在不同的队列中。
所以阻塞就是不被调度时的状态,当前进程的结构体需要在某种被OS管理的资源下排队。
2、阻塞挂起
假设电脑在下载游戏,网络有些不好,断了,此时CPU就断开了和进程的连接,这个进程就找到对应的pcb,与网卡资源连接去了,这时候进程是阻塞状态。过了一会,内存资源变得非常多,系统处理负担大,这时候系统会把不被调度的进程的代码和数据放回到磁盘,释放了内存空间,这时候进程就处于阻塞挂起状态,如果资源等待好了,那么又会把代码和数据拿回到内存,再次被调度,这时候就退出了阻塞挂起状态。
2、Linux进程状态
1、R和S状态
task_struct里面包含很多进程的属性。
系统在运行时会调度一个运行队列,队列的每个进程都有自己的pcb,只要在队列中,那么所有进程都是R状态,然后cpu从中选择一个进行调度即可。进程什么状态,要看它在哪里排队。
int main()
{
while(1)
{
printf("我在运行吗???");
}
return 0;
}
如果我们写了一个死循环,程序会一直打印,但是这时候观察它的状态却不是R而是S+。+先不管,这里出现了一个不是R的状态。把printf注释掉,再次运行程序,这时候它又是R+状态了,+也不管,现在是我们预想到的状态了。
printf是一个向显示器打印的函数,也就是和外设交互,在无限死循环中,外设的速度比不过CPU,那么会有很多时间进程都不在CPU里,而是被放到了外设里,等待显示器准备好,也就是形成了阻塞状态,S是休眠状态,阻塞的一种。而取消访问外设的代码后,程序没有调用外设资源的动作,只有调用CPU资源的动作,所以这时候一直处于R状态。
进程处于R状态,代表进程在运行队列中,这个队列由操作系统维护。S状态是可以终断的。
2、D状态
D状态是不可中断的休眠状态。
假设进程要往磁盘写入100MB的数据,那么它会访问磁盘,开始写入,写完后CPU才会调度这个进程,然后进程就会等待磁盘写入。这时候内存资源如果很紧张,系统会杀掉休眠的进程,如果磁盘对于写数据有问题返给进程,但是进程没了,这时候整个体系就崩掉了。所以为了解决这个问题,像这样的进程应处于D状态,系统不能杀死它。
3、T状态
暂停状态。在运行一个进程时,我们用kill命令,kill有很多功能,后面跟数字,以及进程PID,这里用kill -19 PID,进程就停止了,并且状态变为了T状态,再次发18这个命名,进程又会继续了,这时候再查状态就是S状态了。进程继续,如果用Ctrl + c会发现进程无法退出,并且T之后,查到的状态就是S而不是S+,这是因为有+号表明这是在前台运行,没有则是在后台,Ctrl + c无法停止前台程序,用kill的9号命令即可无差别停止这个程序。
如果用户访问不该访问的东西,系统也会暂停这个进程。调试时遇到断点停止,也是进程被暂停了。
4、X和Z状态
X状态是死亡状态。一个程序终止时,程序瞬间变为X状态,难以查到。Z状态是僵尸状态。
写代码时,非void类型的函数会有返回值,返回值的那一行代码就是进程退出码,Linux可用echo $?来查看返回值。Linux在进程退出的时候,不会立即进入X状态,而是进入Z状态,方便父进程读取子进程退出的退出结果。
但是Z状态的进程越来越多,且一直不释放的话,就会造成内存泄漏。
假设有一个父子进程,父进程先退出,另一边我们可以看到两个进程的实时情况,这时候没有父进程情况后,父进程就直接消失了,而没有展现僵尸状态,是因为这个父进程是有bash回收的,它有人回收,所以没有僵尸状态。父进程没有后,子进程还是会继续运行,但它新的父进程的PID就变成了1,这个1可以理解为操作系统。这个子进程此时就是孤儿进程,被系统领养。如果不认新的父进程,那么这个子进程退出时就会一直在内存中存在,占据资源。
下一篇写环境变量。
结束。