• 【Linux】进程的概念|查看进程的方法|子进程


    ➡️基本概念

    在了解进程之前需要知道什么是程序?
    对于计算机而言,程序就是系统可以识别的一组有序的指令。程序能指挥计算机执行我们想要它做的动作。程序储存在磁盘上,在执行时从磁盘到内存再到寄存器,最后被CPU执行。
    进程的课本概念:程序的一个执行实例,正在执行的程序等,但这只是课本的概念。

    “先描述”进程(PCB)

    不可能在内存上只有一个进程,一般有很多程序在运行,那么操作系统怎么对这些进程进行管理呢?

    一谈到操作系统的管理那么就一定是先描述。再组织,就像这样的先描述再组织的方式是操作系统一贯的作风。不了解先描述再组织的老铁可以看这篇文章文章链接

    把程序加载到内存可不仅仅是把代码拷贝到内存,操作系统为了维护和管理这个进程也要创建对应的管理数据结构,就是这里的PCB(process control block),在Linux操作系统中描述进程的结构体叫做task_struct。
    进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
    本质上是一个装有进程属性的结构体。task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。一个程序对应一个task_struct结构体对象。

    task_ struct内容分类

    • 标示符: 描述本进程的唯一标示符,用来区别其他进程。
    • 状态: 任务状态,退出代码,退出信号等。
    • 优先级: 相对于其他进程的优先级。
    • 程序计数器: 程序中即将被执行的下一条指令的地址。
    • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
    • 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
    • I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
    • 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
    • 其他信息

    “再组织”进程

    可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct链表的形式存在内核里,
    将程序对应一个task_struct结构体对象与它自己的代码和数据关联起来,根据程序对应PCB(task_struct)优先级和各种属性的不同,CPU对他们进行着不同的操作。

    在这里插入图片描述

    最终结论:

    现在返回来看什么是进程,现在对于进程的概念就应该是:内核数据结构(task_struct)+进程对应的磁盘代码

    进程的一些特性:

    1️⃣竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
    2️⃣独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
    3️⃣并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
    4️⃣并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。

    ➡️如何查看进程

    在window下我们可以直接通过任务管理器查看进程。
    在这里插入图片描述
    在Linux下如何查看进程呢?

    方法一:

    我这里先创建一个死循环程序
    在这里插入图片描述
    然后运行程序,在命令行输入

    ps ajx |head -1 && ps ajx |grep 'myproc'
    或者
    ps ajx |head -1 && ps ajx |grep "myproc"
    或者用shell脚本设置一个循环来死循环打印进程信息
    while :; do ps axj |  head -1&& ps axj |grep myprocess | grep  -v grep; sleep 1; done
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    在这里插入图片描述
    PPID是父进程IDPID是这个进程自己的ID,PGID是这个进程的组ID,STAT代表这个进程的状态
    UID是用户ID,COMMAND就代表我是哪一个进程

    想杀掉这个进程用kill -9 这个进程的PID
    在这里插入图片描述

    方法二:

    进程的信息可以通过 /proc 系统文件夹查看。
    在这里插入图片描述
    其实一个一个的进程也就相当于/proc下的一个个目录

    ➡️通过系统调用获取进程标识符

    • 如:要获取PID为1的进程信息,你需要利用cd /proc/1查看/proc/1这个文件夹。 那么怎么在程序里就直接获取PID呢?

    其实Linux提供了一个系统调用接口,叫做getpid()
    运行man getpid认识一下getpid()

    在这里插入图片描述
    在我们的程序里添加这个系统调用,就会自动把当前程序的PID显示出来。
    在这里插入图片描述
    在这里插入图片描述
    当我们利用kill -9 命令将这个11167的进程杀掉之后,那么在/proc下就看不到11167这个目录了。

    然后我们再使用一下getppid来获取一下当前进程的父进程,

    在这里插入图片描述
    通过编译之后,多次运行,我们可以发现,PID也就是下面的id号是运行一次就变一次,而父进程pid号7139是一直都不变的,那么为什么呢?
    在这里插入图片描述
    我们在命令行输入ps ajx | head -1 && ps ajx | grep 7139
    在这里插入图片描述
    就可以看到7139是一个bash,我们把这个bash用kill命令杀掉的话,那我们的各种ls、cd等等一些个命令都运行不了了,我们退出shell下次再进行这样的操作,发现他们的父进程还是bash,所以其实在Linux命令行上启动的进程, 一般它的父进程没有特殊情况的话,都是bash!

    ➡️通过系统调用创建进程子进程(fork)

    • 运行 man fork 认识fork
      在这里插入图片描述
    • 下面是fork的返回值,惊奇的发现fork竟然有两个返回值
    RETURN VALUE
           On success, the PID of the child process is returned in the parent, 
           and 0 is returned in the child.  
           On failure, -1 is returned in the parent, no child process is created, and
           errno is set appropriately.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 父子进程代码共享,数据各自开辟空间,私有一份。fork执行之前只有一个父进程,函数执行之后是父进程+子进程

    实验一:

    下面用vim工具写一段代码:

    在这里插入图片描述
    运行起来可以看到printf被执行了两次,其中上面是父进程打印的,下面的是子进程打印的

    在这里插入图片描述
    通过ps ajx| head -1 && ps ajx | grep 29346查看这个29346是谁,从下面结果就可以清晰的看到它是bash
    在这里插入图片描述
    从上面的结果来用一句形象的话来描述上面的现象就是:29945是爸爸,29346(bash)是爷爷,29946是孩子。

    实验二:

    代码:
    在这里插入图片描述
    执行结果:
    在这里插入图片描述

    RETURN VALUE
           On success, the PID of the child process is returned in the parent, 
           and 0 is returned in the child.  
           On failure, -1 is returned in the parent, no child process is created, and
           errno is set appropriately.
    
    • 1
    • 2
    • 3
    • 4
    • 5

    通过前面的介绍已经知道fork是有两个返回值的,可以看到其实它一个返回值返回给了父进程,这个返回值从上面可以看出它是子进程的id,另一个返回值是0,被返回给了子进程。

    • fork 之后通常要用 if 进行分流

    实验三:

    代码:
    在这里插入图片描述
    执行结果:
    在这里插入图片描述
    可以看到在fork之后,会有父进程+子进程连个进程在执行后续代码。fork之后的代码,被父子进程共享,通过返回值的不同,让父子进程执行后续共享的代码的一部分。这就叫所谓的并发式编程。

  • 相关阅读:
    APIMapper 源码解析
    【工作总结】努力工作为什么感觉没用
    创建Vue项目的常用npm插件总结
    Mac上使用FFmpeg
    03-04-Spring声明式事务
    ZYNQ7020--动态加载CPU1程序<1>
    【Leetcode】 707. 设计链表
    跨机器检查基于DCLI命令
    eachers地图的配置
    QGIS添加在线底图
  • 原文地址:https://blog.csdn.net/qq_55712347/article/details/128140069