进程的状态

进程的状态,第1张

进程状态
  • 意义
  • 具体状态
    • 状态演示
      • R状态
      • S状态
      • Z状态
      • 孤儿进程
  • kill命令
    • 常见kill命令使用
      • kill -19:暂停进程
      • kill -18:继续进程
  • 运行队列和等待队列


如上,这是一幅常见的进程执行状态的示意图,在进程控制块一节中讲过进程的状态信息存储在task_struct也就是PCB 中。


意义

进程状态的意义:方便 *** 作系统快速判断进程,完成特定的功能,比如调度,本质是一种分类

具体状态

R:运行态,不一定正在占用CPU: 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里
S:睡眠状态,意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠
D:磁盘休眠状态:有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的 进程通常会等待IO的结束,进程如果处于D状态,不可被杀掉。



T:暂停状态,彻底的暂时进程的数据不会更新
t:追踪状态
X:死亡状态,死亡需要回收进程资源
Z:僵尸状态,为什么要有僵尸状态,为了辨别退出死亡原因,进程退出的信息(在task_struct),正常程序退出先进入Z状态把进程退出信息保存到PCB当中,再进入X死亡状态退出

状态演示 R状态

测试代码如下:

#include
#include
int main()
{
  while(1)
  {
  }
  return 0;
}

使用
while :; do ps axj | head -1 && ps axj | grep test ; sleep 1; echo "###########################";done,该命令进行监控程序运行情况。




可以看到当前进程处于运行状态,后面的+代表在前台运行

S状态

测试代码如下:

#include
#include
int main()
{
  while(1)
  {
   printf("pid:%d\n",getpid());
   printf("ppid:%d\n",getppid());
  }
  return 0;
}


运行结果如上所示,这里我们看到,这个程序是在不断打印的状态下,应该是处于R状态才对,但是为什么是S状态呢?原因是IO等待外设是需要时间的,因此看起来像是一直在运行实际上一直在等待。


Z状态

僵死状态(Zombies)是一个比较特殊的状态。


当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程
僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。



所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态
测试代码:

#include
#include
int main()
{
  pid_t id=fork();
  if(id==0)
  {
    //child
      printf("i am child\n");
  }
  else 
  {
      //father
    printf("i am father\n");
    sleep(50);
   }
  return 0;
}

这里的代码是让子进程先结束,父进程等待50s后在结束

这里可以看到子进程结束后没有进程对其进行回收,因此进入僵尸状态

僵尸进程危害:
进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),交给他的任务,办的怎么样了。


可父进程如果一直不读取,那子进程就一直处于Z状态。



维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护。



那一个父进程创建了很多子进程,就是不回收,就会造成内存资源的浪费。


因为数据结构
对象本身就要占用内存,C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!

孤儿进程

父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?
父进程先退出,子进程就称之为“孤儿进程”,孤儿进程被1号init进程领养,当然要有init进程回收喽。



测试代码如下:

#include
#include
int main()
{
  pid_t id=fork();
  if(id==0)
  {
    //child
   // while(1)
    
      printf("i am child\n");
    sleep(10);
  }
  else 
  {
      //father
    printf("i am father\n");
   sleep(3);
   }
  return 0;
}

这里我们让父进程先于子进程退出,通过查看运行状态我们可以看到,在父进程退出后,子进程的ppid变为1说明子进程被1号进程回收

kill命令

kill -l:显示kill命令类型

常见kill命令使用

测试代码如下:

#include
#include
int main()
{
  while(1)
  {
   printf("pid:%d\n",getpid());
   printf("ppid:%d\n",getppid());
  }
  return 0;
}

kill -19:暂停进程


此时进程状态变为T状态。


kill -18:继续进程


这里需要注意的是,这里的进程状态变为R状态没有带+号说明该进程在后台运行,这时候没办法使用CTRL+c来终止进程,可以使用kill -9来杀死进程,或者可以使用fg命令,将后台进程变为前台进程,在使用ctrl+c杀死进程

运行队列和等待队列

等待cpu资源的时候被称为运行队列。



等待其他资源的时候被称为等待队列。



所谓的进程,在运行的时候可因为运行需要可能在不同的队列中,在不同的队列中所处的状态是不一样的
我们把从运行状态的task_struct放到等待队列中,就叫做挂起等待(阻塞)。



从等待队列放到运行队列,被CPU调度叫做唤醒进程。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/langs/569278.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-09
下一篇 2022-04-09

发表评论

登录后才能评论

评论列表(0条)

保存