【Linux系统化学习】进程的状态 | 僵尸进程 | 孤儿进程

简介: 【Linux系统化学习】进程的状态 | 僵尸进程 | 孤儿进程

操作系统进程的状态

caf5ab725be94bd7bf0080d4c66b85a6.png


进程状态:一个进程的生命周期可以划分为一组状态,这些状态刻画了整个进程。进程状态即体现一个进程的生命状态。

一个可执行程序加载到内存中,操作系统会创建一个PCB里面存放着各种属性、PID、PPID等;进程的状态也就是一个字段/变量在PCB中,不同的值代表不同的状态。

操作系统进程的主要状态包括,运行状态、阻塞状态、挂起阻塞状态

运行状态

当我们的可执行程序加载到内存中,需要CPU进行数据运算时会从内存调度到CPU中;当然CPU的处理数据的能力是有限的,而当有很多的程序被调度时候,会将每个可执行程序的PCB使用链表建模依次等待CPU的调度;也就是我们之前提到的进程在”排队“;因此只要在CPU运行的队列中的进程,都是运行状态。

阻塞状态

我们自己编写的可执行程序难免会对系统中的资源进行访问,像我们需要使用输入函数cin/scanf从键盘输入一些数据时候就是可执行程序从键盘中读取数据;那么我们一直不输入数据,键盘中的数据就一直没有准备就绪,也就是进程访问的资源没有就绪,那么后序的代码就执行不了了。

当然我们的操作系统此时可不止这一个进程需要对系统中某个设备的资源进行访问,这就有需要一个队列建模需要访问资源的进程的PCB,此时这个队列就不再等待CPU调度的队列中了;因此我们把进程PCB链入非CPU的运行队列而把PCB链入到各种设备所维护的等待队列当中去等待资源就绪时的状态叫做阻塞状态。

·       进程的PCB从CPU调度的等待队列中转移到各种设备的等待队列中叫做该进程阻塞了。

·       当从设备中拿到数据是PCB会从设备的等待队列转移到CPU的调度队列这个过程叫做将该进程唤醒。

进程阻塞的现象

·       进程卡住了

·       PCB不在运行状态中&&状态不是running,进程不在被CPU调度

挂起阻塞状态

挂起阻塞状态时阻塞状态的一种特殊情况,当我们的PCB在阻塞状态时操作系统的内存严重不足时,会将次PCB对应加载到内存中的程序移出内存放回磁盘,当PCB读取到数据时需要被CPU调度时又将程序加载到内存中。

总结

进程状态变化的本质

·       更改PCB中status的整数变量

·       将PCB链入不同的队列中

·       只和进程的PCB有关,和进程的代码数据无关。


Linux进程状态

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 */
};
  1 #include<stdio.h>
  2 int main()
  3 {
  4     while(1)
  5     {
  6         printf("我是一个进程\n");                                                               
  7     }
  8     return 0;
  9 }

c946df02d83142578ad0f226d0c46632.png

因为我们的进程在疯狂的printf时,本质是往显示器上面打印,进程是在内存中是将内存中的数据向外刷新;当刷新时,显示器不一定准备好,因此在程序运行中大部分是S状态。

R(running状态)运行状态

 

  1 #include<stdio.h>
  2 int main()
  3 {
  4     while(1)
  5     {
  6        // printf("我是一个进程\n");                                                             
  7     }                               
  8     return 0;                       
  9 }                                   

af56dc16620d466b9b240d6e4f892574.png

这样我们就可以查到R状态的进程了;

S(sleeping)休眠状态

浅度睡眠

 

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 int main()
  4 
  5 {
  6     int a=0;
  7     printf("请输入一个数字:");
  8     scanf("%d",&a);
  9     printf("%d\n",a);                                              
 10 
 11     return 0;
 12 }

a1fc477c77b74cfaaa3cd350274f39d3.gif

浅度休眠状态可以被终止,可以被kill掉;并且会对外部状态做出相应。

D(desk sleep)磁盘休眠

深度睡眠

·       针对磁盘来设计的,不可能被kill掉,操作系统也不可以;

·       我们很难查到D状态,如果被用户查到计算机几乎快要宕机了。

T(stopped)

暂停一个进程。

 59a5a87dbc1a4a27b833fdd7428a040d.gif

t(tracing stop

适用于我们debug模式下调试代码追踪我们的进程暂停下来。

等待软件条件。

 04e69b095330497599297289e6162127.png

x(dead)


这个状态只是一个返回状态,不会查看到这个进程的。


僵尸进程(zombie

zzombie

可执行程序加载到内存中成为进程,操作系统创建PCB,内存里的进程肯定是完成某种任务得到某种结果的;当进程退出时总要返回一些信息告诉操作系统任务完成的怎样;就像我们写的代码总要在最后一行return 0;退出信息会由操作系统写入到PCB中,此时内存中进程的代码和数据被释放,但是不允许PCB释放;需要操作系统读取PCB进程的退出信息,得知进程退出的原因后PCB才会被释放。因此当进程被释放后而PCB没有被释放的这段空窗期成为僵尸进程。

·       僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程

·       僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。

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

僵尸状态演示

 

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 int main()
  5 {
  6     pid_t id =fork();
  7     if(id<0)
  8     {
  9         return 1;
 10     }
 11     else if(id==0)
 12     {
 13         int n=5;
 14         while(n)
 15         {
 16             printf("我是一个子进程:%d\n",n--);
 17             sleep(1);
 18         }
 19         exit(2);                                                                                
 20     }
 21     else{
 22         while(1)
 23         {
 24         printf("我是父进程\n");
 25         sleep(1);
 26         }
 27     }
 28     return 0;
 29 }

6e0e89f618ca44d983e64b5e7befc467.png

僵尸进程的危害

·       进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!

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

·       那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!

·       内存泄漏!!!


孤儿进程

·       孤儿进程和僵尸进程刚好相反,父进程先退出,子进程称之为”孤儿进程“。

·       孤儿进程会被系统进程”领养”,最中由init进程回收,init进程为我们所有进程的起源。

孤儿进程演示

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 int main()
  5 {
  6     pid_t id =fork();
  7     if(id<0)
  8     {
  9         return 1;
 10     }
 11     else if(id==0)
 12     {
 13         while(1)
 14         {
 15         printf("我是一个子进程\n");
 16         sleep(1);                                                      
 17         }
 18     }
 19     else{
 20         int n=5;
 21         while(n)
 22         {
 23             printf("我是一个父进程:%d\n",n--);
 24             sleep(1);
 25         }
 26         exit(2);
 27         }
 28     return 0;
 29 }

c7103a0ee09f4c0ba1bbd08d1ede95c2.png前台进程和后台进程

 

4de8e1af0d6c4322995a600e598652a1.gif

当我们运行我们编译好的代码后无论输入任何指令系统都不会有任何反应,但是可以通过Ctrl+C来终止 。并且状态带有+ ,这就是前台状态

 

4e3a216846c1495c926321dd86225213.gif

3cb22ed7911548adb277faf20de268b8.png

在编译好的代码后加上&操作符进行执行,代码不仅可以执行而且输入的指令也可以识别,但是不可以使用CTRL+C终止掉,这就是后台状态 

相关文章
|
5天前
|
NoSQL 关系型数据库 MySQL
Linux学习记录---(1、基本命令)
该博客文章提供了Linux系统中基本命令的使用记录,包括文件和目录操作、Redis服务管理、MySQL数据库操作以及Tomcat服务器的启动和检查。
Linux学习记录---(1、基本命令)
|
28天前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
23天前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
30 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
18天前
|
算法 Linux 调度
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。
|
18天前
|
安全 开发者 Python
揭秘Python IPC:进程间的秘密对话,让你的系统编程更上一层楼
【8月更文挑战第1天】在系统编程中, 进程间通信 (IPC) 是连接独立进程的关键技术, 提升了系统的并发性和灵活性。Python 提供了丰富的 IPC 机制, 包括管道 (`Pipe`), 队列 (`Queue`), 共享内存 (`Value`, `Array`) 和套接字 (`Sockets`)。这些机制支持不同的应用场景, 如简单的父子进程通信或复杂的分布式系统构建。合理选择 IPC 方法可帮助开发者构建高效、可靠的多进程应用, 但同时也需注意同步和数据一致性等问题。
30 1
|
26天前
|
算法 调度 UED
操作系统中的进程调度策略及其对系统性能的影响
本文深入探讨了操作系统中进程调度的多种策略,包括先来先服务、短作业优先、优先级调度、轮转与多级队列等,并分析了它们对系统性能的具体影响。通过比较不同调度算法的效率和公平性,本文旨在为系统管理员提供选择合适调度策略的依据,以优化系统的整体表现。
|
27天前
|
Ubuntu 算法 Linux
嵌入式Linux的学习误区
**嵌入式Linux学习误区摘要** 1. **过度聚焦桌面Linux** - 许多学习者误将大量时间用于精通桌面Linux系统(如RedHat、Fedora、Ubuntu),认为这是嵌入式Linux开发的基石。 - 实际上,桌面Linux仅作为开发工具和环境,目标不应是成为Linux服务器专家,而应专注于嵌入式开发工具和流程。 2. **盲目阅读Linux内核源码** - 初学者在不了解Linux基本知识时试图直接研读内核源码,这往往导致困惑和挫败感。 - 在具备一定嵌入式Linux开发经验后再有针对性地阅读源码,才能有效提升技能。
22 4
|
1月前
|
Ubuntu 应用服务中间件 Linux
Linux学习之Ubuntu 20中OpenResty的nginx目录里内容和配置文件
总的来说,OpenResty的Nginx配置文件是一个强大的工具,它允许你以非常灵活的方式定义你的Web服务的行为。
24 2
|
3月前
|
Linux 调度
【Linux】详解进程状态之僵尸进程——孤儿进程
【Linux】详解进程状态之僵尸进程——孤儿进程
【Linux】详解进程状态之僵尸进程——孤儿进程
|
3月前
|
Linux Shell 调度
【Linux】进程排队的理解&&进程状态的表述&&僵尸进程和孤儿进程的理解
【Linux】进程排队的理解&&进程状态的表述&&僵尸进程和孤儿进程的理解