当前位置:   article > 正文

Linux——进程概念(进程状态)_kill -18

kill -18

目录

进程状态

三态模型

五态模型

七态模型

Example

eg1:阻塞态:等待某种资源的过程

eg2:挂起态

Linux内核源代码

Linux进程状态查看

Linux运行状态

R运行状态(running):

S睡眠状态(sleeping):

 D磁盘休眠状态(Disk sleep):

T停止状态(stopped):

kill -19 SIGSTO(暂停stop)

kill -18 SIGCONT(继续continue)

 kill -9 SIGKIL(kill)

X死亡状态(dead):

 Z(zombie)-僵尸进程:

孤儿进程


进程状态

三态模型

进程状态分为 运行态,就绪态,阻塞态。

五态模型

进程状态分为 新建态、终止态,运行态,就绪态,阻塞态。

七态模型

进程状态分为 挂起就绪态、挂起等待态、新建态、终止态,运行态,就绪态,阻塞态

Example

eg1:阻塞态:等待某种资源的过程

        操作系统对外设的管理先描述再组织,操作系统有对应的结构体对外设进行管理,每个管理外设的结构体都有一个等待队列,这些结构体对需要访问该外设的进程进行管理,而等待的进程就被放入等待队列,进而变成阻塞状态,当相应的外设进行相关的操作,PCB(含有全部的属性和数据)便会被CPU执行
        进程因为等待某种条件就绪,而导致的一种不推进的状态——进程卡住了
         阻塞——不被调度——一定是因为当前进程需要等待某种资源(磁盘、网卡、显卡等各种外设)就绪——一定是进程task_struct结构体需要在某种被OS管理的资源下排队
        为什么阻塞?进程要通过等待的方式,等具体资源被别人用完之后,再被自己使用

 PCB可以被维护在不同的队列中

资源线性申请

eg2:挂起态

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 */
};

Linux进程状态查看

ps aux / ps axj     

Linux运行状态

R运行状态(running):

并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。

传统意义上新建态、就绪态在Linux中就是R状态

我们来看两段代码
  • 含printf的循环
  1. #include <stdio.h>
  2. int main()
  3. {
  4. while(1)
  5. {
  6. printf("我在运行吗??\n");
  7. }
  8. }
 //printf 本质就是向外设打印消息,循环打印的过程中外设不会一直处于运行状态,所处理的代码在等待队列中(CPU执行速度非常快)
  •  不含printf的纯循环
  1. int main()
  2. {
  3. while(1)
  4. {
  5. //printf("我在运行吗??\n");
  6. }
  7. }

 不含printf的纯循环,只需要进行判断,一个纯计算使用CPU不需要使用外设资源的代码,所以就是R状态

S睡眠状态(sleeping):

意味着进程在等待事件完成(本质是一种阻塞状态)

(这里的睡眠有时候也叫做可中断睡眠 (interruptible sleep))。

  1. #include <stdio.h>
  2. int main()
  3. {
  4. while(1)
  5. {
  6. int a=0;
  7. scanf("%d\n",&a);
  8. printf("%d\n",a);
  9. //printf("我在运行吗??\n");
  10. }
  11. }

 等待键盘输入,等待键盘资源

 D磁盘休眠状态(Disk sleep):

        有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。

        我们来举个例子:假如现在有个进程,想向内存写入一个巨大的数据,磁盘将这些数据进行储存,而该进程等待磁盘工作完成并且在等待队列中等待,该进程S休眠,此时CPU执行其他的代码。此时操作系统路过,看到内存严重不足,并且看到该进程尚未执行,什么都不做,Linux就将其删除,当磁盘写完后,发现家被偷了,为了避免这种情况发生,我们保证在某种状态下,即便是操作系统,该进程在这种状态下也无法被杀死,这种状态即为D磁盘休眠状态

T停止状态(stopped):

        可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

  1. #include <stdio.h>
  2. 2 #include<unistd.h>
  3. 3
  4. 4 int main()
  5. 5 {
  6. 6 while(1)
  7. 7 {
  8. 8 // int a=0;
  9. 9 // scanf("%d\n",&a);
  10. 10 //
  11. 11 // printf("%d\n",a);
  12. 12 //
  13. 13 printf("我在运行吗??,%d\n",count++);
  14. 14 sleep(1);
  15. 15 }
  16. 16 }

kill -19 SIGSTO(暂停stop)

kill -18 SIGCONT(继续continue)

 但是当我们control C时,仍然执行

注:control C只能中断在前台运行的代码,即我们显示状态的时候后方跟了+号的进程,由此可以解释之前显示状态的时候,为何S+后有一个+号,为了中断进程,不论前台或者后台的我们都可以使用kill -9 PID

 kill -9 SIGKIL(kill)

 "t (tracing stop)", /* 8 */ 追踪暂停也是暂停的一种,断点处停下来,本质就是进程暂停

X死亡状态(dead):

        这个状态只是一个返回状态,你不会在任务列表里看到这个状态 

 Z(zombie)-僵尸进程:

       
         僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲),没有读取到子进程退出的返回代码时就会产生僵死(尸)进程 ,僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
        所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态来维持进程
         我们创建进程是为了让进程 帮助我们办事,而对于我们操作者而言,我们可能关心结果,也可能不关心结果;当我们是前者的时候,我们可以使用printf来查看结果,但是需要认为校验结果的准确性,我们也可以通过进程退出码来判断,如果一个进程退出了,立马X状态,立马退出,有没有机会拿到退出结果???Linux当进程退出的时候,一般不会立即彻底退出,而是要维持一个状态叫做,也叫做僵尸状态——方便后续父进程(OS)读取该子进程退出的退出结果
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
如何看到僵尸的状态??子进程退出,但是不要收回子进程
  1. int main()
  2. {
  3. pid_t id =fork();
  4. if(id==0)
  5. {
  6. //子进程
  7. while(1)
  8. {
  9. printf("我是子进程,我在运行,pid:%d,ppid: %d\n",getpid(),getppid());
  10. sleep(1);
  11. }
  12. }
  13. else if(id>0)
  14. {
  15. //父进程
  16. while(1)
  17. {
  18. printf("我是父进程,我在运行,pid: %d, ppid: %d\n",getpid(),getppid());
  19. sleep(1);
  20. }
  21. }
  22. }

         我们kill -9 子进程,发现变成了Z+
         维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护,僵尸状态资源没回收完,如果一个父进程创建了很多子进程,就是不回收,就是不释放,会使得内存可用的越来越少,因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!不释放涉及内存泄漏等知识

孤儿进程

父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?
父进程先退出,子进程就称之为“孤儿进程”
父进程退出,子进程就会被OS自动领养(通过让1号进程成为新的父进程)。
  1. int main()
  2. {
  3. pid_t id =fork();
  4. if(id==0)
  5. {
  6. //child
  7. while(1)
  8. {
  9. printf("我是子进程:pid: %d, ppid: %d\n",getpid(),getppid());
  10. sleep(1);
  11. }
  12. }
  13. else
  14. {
  15. //parent
  16. int cnt=10;
  17. while(1)
  18. {
  19. printf("我是父进程:pid: %d, ppid: %d\n",getpid(),getppid());
  20. sleep(1);
  21. if(cnt--<=0)break;
  22. }
  23. }
  24. return 0;
  25. }

 父进程的僵尸状态未被看见,因为其被其父进程即bash回收

32516的爹嘎了之后,又给自己找了一个爹,PPID为1

 为什么领养?如果不领养,子进程后续再退出,无人回收,游离的进程多了,占据更多的内存空间。

       并且我们可以看到,领养之前,子进程S+前台运行,领养之后,自动由前台变为后台运行,如果想杀掉该进程

  • kill -9 PID
  • killall myproc(进程名称)
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/334757
推荐阅读
相关标签
  

闽ICP备14008679号