Linux下进程以及相关概念理解(一)

简介: Linux下进程以及相关概念理解

一、进程概念

课本概念:程序的一个执行实例,正在执行的程序等

内核观点:担当分配系统资源(CPU时间,内存)的实体

当代码进行编译链接等操作后就会生成一个可执行程序,这个可执行程序本质上也是一个文件,存放在磁盘上。当使这个可执行程序运行起来,本质上是将这个程序加载到内存当中了,因为只有加载到内存后,CPU才能对其进行逐行的语句执行,而一旦将这个程序加载到内存后,我们就不应该将这个程序再叫做程序了,严格意义上将应该将其称之为进程。

并且进程与程序并不一定是对应的,一个程序可以同时运行多次,也就有了多个进程。

竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

二、描述进程PCB

我们的电脑上存在着大量的进程,这时就需要操作系统来进行管理。如何管理呢?先描述,再组织

操作系统将每一个进程都进行描述,形成了一个个的进程控制块(PCB,本质上是一个结构体),并将这些PCB以双向链表的形式组织起来。


26b0cfc5028c4947b84227a31ca9fb7a.png


PCB实际上是对进程控制块的统称,Linux当中的进程控制块为 task_struct,task_struct当中主要包含以下信息:

标示符:描述本进程的唯一标示符,用来区别其他进程。

状态:任务状态,退出代码,退出信号等。

优先级:相对于其他进程的优先级。

程序计数器(pc):程序中即将被执行的下一条指令的地址。

内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。

上下文数据:进程执行时处理器的寄存器中的数据。

I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。

记账信息:可能包括处理器时间总和,使用的时钟总和,时间限制,记账号等。

其他信息: ……


三、查看进程

3.1 通过系统目录查看

在根目录下有一个名为proc的系统目录,该目录中包含大量进程信息。其中有些子目录的目录名为数字,这些数字其实是某一进程的PID,对应文件夹当中记录着对应进程的各种信息。若想查看PID为1的进程的进程信息,则查看名字为1的文件夹即可。

2e39ecb020b44863b26ea91b9367460d.png

3.2 通过ps命令查看

ps命令的具体使用可以使用man 1 ps命令查看文档

bb3aa23a9ed546cb850e7cf8b1b5e44a.png

b08eb70517c64dd0ad32247576717e76.png


在Linux操作系统下使用ps -l命令会出现下列这种情况。

1e97c0c2409f4adc9f11df625ce3b1b3.png


UID:代表执行者的身份。

PID:代表这个进程的代号。

PPID:代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号。

PRI:代表这个进程可被执行的优先级,其值越小越早被执行。

NI:代表这个进程的nice值。

四、进程状态


ce25306daa0b42bf93653cfee22670c0.png

Linux操作系统的源代码当中对于进程状态有如下定义:

static const char *task_state_array[] = {
  "R (running)",       /*  0*/
    "S (sleeping)",      /*  1*/
    "D (disk sleep)",    /*  2*/
    "T (stopped)",       /*  4*/
    "T (tracing stop)",  /*  8*/
    "Z (zombie)",        /* 16*/
    "X (dead)"           /* 32*/
};

运行状态R

所有处于运行状态的进程(即可被调度的进程),都被放到运行队列当中。当操作系统需要切换进程运行时,就直接在运行队列中选取进程运行。一个进程处于运行状态(running),并不意味着进程一定处于运行当中。运行状态表明一个进程要么在运行中,要么在运行队列里。即可以同时存在多个R状态的进程


睡眠状态S

意味着进程在等待事件完成(该睡眠状态也可称为可中断睡眠)


譬如当进程循环向屏幕输出时,由于CPU的处理速度极快,但显示器的速度较慢,导致进程需等待显示器这个资源(CPU此时会处理别的进程)。此时该进程会在运行状态和睡眠状态不断切换,但由于CPU的高速导致我们观测时大概率会看见睡眠状态

#include <stdio.h>
int main()
{
    while(1){
         printf("handsome boy!\n");                                                                                                                                                                    
    }
    return 0;
}       

a5c941d952344a918b9a77a73f4d09f8.png


显示状态时有个+号表示该进程是前台进程,若没有则是后台进程。


处于该睡眠状态下的进程是可以被杀死的,譬如使用kill命令发送信号


磁盘休眠状态D

一个进程处于磁盘休眠状态,表示该进程不会被杀掉,即便是操作系统也不行,只有该进程自动苏醒才可以杀死 。也可称为不可中断睡眠状态(uninterruptible sleep),处于这个状态的进程通常会等待IO的结束。


譬如,某一进程要求对磁盘进行写入操作,那么在磁盘进行写入期间,该进程就处于深度睡眠状态,是不可被杀掉的。因为该进程需要等待磁盘的回复(是否写入成功)以做出相应的应答。


使用dd命令可以模拟磁盘休眠状态


暂停状态T

在Linux当中,我们可以通过发送SIGSTOP信号使进程进入暂停状态,发送SIGCONT信号可以让处于暂停状态的进程继续运行。


250cd9426e894641855bf017338219b6.png


僵尸状态Z

当一个进程将要退出的时候,在系统层面,该进程曾经申请的资源并不是立即被释放,而是要暂时存储一段时间,以供操作系统或是其父进程进行读取,如果退出信息一直未被读取,则相关数据是不会被释放掉的,一个进程若是正在等待其退出信息被读取,那么我们称该进程处于僵尸状态。(进程的退出信息存储在该进程的task_struct中)


僵尸状态的存在是必要的,因为进程被创建的目的就是完成某项任务,那么当任务完成的时候,调用方是应该知道任务的完成情况的,所以必须存在僵尸状态,使得调用方得知任务的完成情况,以便进行相应的后续操作。


死亡状态X

死亡状态只是一个返回状态,当一个进程的退出信息被读取后,该进程所申请的资源就会立即被释放,该进程也就不存在了,所以几乎不会在任务列表当中看到死亡状态。


阻塞(拓展)

进程运行时是被CPU调度的。即进程在调度时是需要用到CPU资源的,每个CPU都有一个运行等待队列(runqueue),CPU在运行时就是从该队列中获取进程进行调度的


e697ebc66eff4d348f0fd360fab590ef.png


在运行等待队列中的进程本质上就是在等待CPU资源,实际上不止是等待CPU资源如此,等待其他资源也是如此,比如锁的资源、磁盘的资源、网卡的资源等等,都有各自对应的资源等待队列


566c6f0034124cb3be4e2faf657f2f36.png


对应到Linux中的状态,阻塞即 睡眠状态S 与 磁盘休眠状态D


五、僵尸进程与孤儿进程

5.1 僵尸进程

5.1.1 僵尸进程的概念

一个进程若是正在等待其退出信息被读取,那么我们称该进程处于僵尸状态。而处于僵尸状态的进程,就是僵尸进程。


如下代码,fork函数创建的子进程在打印5次信息后会退出,而父进程会一直打印信息。即子进程退出了,父进程还在运行,但父进程没有读取子进程的退出信息,那么子进程就进入了僵尸状态。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
  pid_t id = fork();
  if(id == 0)
    {
    int count = 5;
    while(count){
      printf("I am child...PID:%d, PPID:%d, count:%d\n", getpid(), getppid(), count);
      sleep(1);
      count--;
    }
    printf("child quit...\n");
    exit(1);
  }
  else if(id > 0)
    {
    while(1){
      printf("I am father...PID:%d, PPID:%d\n", getpid(), getppid());
      sleep(1);
    }
  }
  else{
        exit(-1);
  }
  return 0;
} 


cc8abfd8cd7c41a89419e64d538befa0.png


5.1.2 僵尸进程的危害

若父进程一直不读取进程的退出信息,那么子进程将一直处于僵尸状态。

僵尸进程的退出信息被保存在task_struct中,若僵尸状态一直不退出,PCB就需一直维护。

若是一个父进程创建了很多子进程,但都不进行回收,那么就会造成资源浪费。

僵尸进程申请的资源无法进行回收,那么僵尸进程越多,实际可用的资源就越少,僵尸进程会导致内存泄漏。

5.2 孤儿进程

若父进程先退出,那么将来子进程进入僵尸状态时就没有父进程对其进行处理,此时该子进程就称之为孤儿进程。若是一直不处理孤儿进程的退出信息,那么孤儿进程就会一直占用资源,此时就会造成内存泄漏。因此,当出现孤儿进程的时候,孤儿进程会被1号init进程领养,此后当孤儿进程进入僵尸状态时就由int进程进行处理回收。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
     pid_t id = fork();
     if(id == 0){ //child
         int count = 5;
         while(1){
             printf("I am child...PID:%d, PPID:%d\n", getpid(), getppid(), count);
             sleep(1);
         }
     }
     else if(id > 0){ //father                                                      
         int count = 5;
         while(count){
             printf("I am father...PID:%d, PPID:%d, count:%d\n", getpid(), getppid(), count);
             sleep(1);
             count--;
         }
         printf("father quit...\n");
         exit(0);
     }
     else{ //fork error
         exit(-1);
     }
     return 0;
}

448773e14a094f7ebd57b07455512239.png


由于孤儿进程会被init1号进程领养,其并不会造成危害。

目录
相关文章
|
10天前
|
存储 负载均衡 Linux
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(下)
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(下)
|
10天前
|
消息中间件 Unix Linux
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(上)
【Linux 系统】进程间通信(匿名管道 & 命名管道)-- 详解(上)
|
3天前
|
算法 Linux 调度
深度解析:Linux内核的进程调度机制
【5月更文挑战第29天】 在现代操作系统中,尤其是类Unix系统如Linux中,进程调度机制是保证多任务高效运行的核心。本文将深入探讨Linux操作系统内核的进程调度器——负责管理CPU资源分配的关键组件。我们会详细分析其调度策略、调度器的演进及其在多核处理器环境下的表现。通过剖析进程调度器的工作原理和设计哲学,旨在为读者提供一个清晰的视角来理解这一复杂的系统功能。
|
4天前
|
存储 调度
进程与线程(概念、并行、并发)
进程与线程(概念、并行、并发)
|
8天前
|
算法 调度
【操作系统】处理机调度的基本概念和三个层次、进程调度的时机和方式、调度器、闲逛线程
【操作系统】处理机调度的基本概念和三个层次、进程调度的时机和方式、调度器、闲逛线程
21 3
|
8天前
|
调度 索引
【操作系统】进程的基本概念&进程的状态与转换&进程的组织方式
【操作系统】进程的基本概念&进程的状态与转换&进程的组织方式
15 2
|
9天前
|
存储 Linux 数据安全/隐私保护
Linux进程间通信
Linux进程间通信
26 6
|
10天前
|
存储 Unix Linux
【Linux 系统】进程信号 -- 详解(下)
【Linux 系统】进程信号 -- 详解(下)
|
10天前
|
NoSQL Linux Shell
【Linux 系统】进程信号 -- 详解(上)
【Linux 系统】进程信号 -- 详解(上)
|
10天前
|
消息中间件 存储 安全
【Linux 系统】进程间通信(共享内存、消息队列、信号量)(下)
【Linux 系统】进程间通信(共享内存、消息队列、信号量)(下)

热门文章

最新文章