当前位置: 首页 > news >正文

【linux进程】深度理解进程--什么是进程什么是pcb进程创建

目录

  • 前言
  • 一,对PCB的理解
  • 二,CPU对进程列表的处理
  • 三,进程标识符:pid
    • 1. 查看系统进程1: ps axj
    • 2. 查看系统进程2: /proc
  • 四,系统调用函数:getpid
  • 五,父进程和子进程的概念
  • 六,创建子进程--fork函数的使用
    • 1. 创建一个子进程并观察
    • 2. fork返回值的理解
    • 3. 进程的独立性

前言

进程这章节的内容是我们学习linux遇到的第一座大山,它的重难点程度不亚于C++中的继承多态。由于它的内容很多,所以也会分多篇文章进行介绍。在学习进程之前,建议同学们先阅读文章对冯诺依曼体系结构和操作系统的理解。

一,对PCB的理解

先简单认识一下进程的概念:

(1) 课本概念:程序的一个执行实例,正在执行的程序等
(2) 内核观点:担当分配系统资源(CPU时间,内存)的实体

同学们肯定是理解不了这种概念的。
我们打开windows的任务管理器:

在这里插入图片描述
这些就是当前我电脑上存在的进程。

结论:操作系统中,进程可以同时存在非常多!

既然有这么多进程同时存在,那操作系统怎么管理这些进程呢?
虽然现在我们不知道什么是进程,但是我们可以通过先描述,再组织这一结论得出,操作系统管理进程肯定也是管理进程对应的数据,请看下图:

在这里插入图片描述
难道这些在内存里的代码和数据就是进程吗?
如果是进程,那问题又来了,这个进程被调度多久时间了,代码/数据是从哪开始到哪结束的,有多个进程时,凭什么优先调度我?这些问题都不能在上图中表示出来。

结论:对于操作系统来讲,这个被加载到内存的可执行程序根本就不是进程!它只是进程对应的代码和数据!

OS为了管理已经被加载进来的进程,都要为每个进程创建一个struct结构体(用来描述),使用链表或其他数据结构将它们链接在一起(用来组织)。

在OS学科中,每个进程都会有一个struct PCB,这个PCB中包含了每个进程的所有属性,也叫进程控制块

struct PCB
{// id// 代码/函数地址// 状态(是否被CPU处理)// 优先级// 内存指针(指向自己的代码和数据)struct PCB* next
}

所以上图可修改为:
在这里插入图片描述

结论:
(1) PCB是在操作系统内部管理进程的内核数据结构。
(2) 进程 = PCB + 自己的代码和数据!
(3) 对进程的管理,就变成了对链表的增删查改!

讲到这里可能同学们还是有点迷糊,现在把它们和我们生活中的事物类比理解:

我们把学校类比成内存,OS类比成学校的教务管理系统,把一个学生类比为加载到内存的代码和数据,而学生在教务系统中的属性信息类比为进程中的PCB在OS的内部。
怎么证明你是这个学校的学生呢?因为你的信息在这个学校教务系统中。
所以OS对进程的管理,本质是对PCB的管理,而并非把可执行程序加载进来对可执行程序进行直接管理!

对PCB的再理解:
PCB是操作系统中的概念(linux中有PCB,windws中也有PCB…),而我们学习的linux操作系统是一款具体的操作系统,在linux系统中具体实现的PCB,叫做 task_struct

struct task_struct
{// linux进程控制块
}

二,CPU对进程列表的处理

进程被链接在链表中会等待CPU去PCB找数据做处理,那么CPU怎么知道要处理哪些数据呢?这不得不提到进程排队的概念:

把对应的PCB从链表中提取到队列中队,PCB中的数据不会一次性被CPU处理完,它有时被处理,有时在等待被处理,这是一种动态运行的特征,请看下图:

在这里插入图片描述
理解进程动态运行:

只要我们的进程task_struct将来在不同的队列中,进程就可以访问不同的资源。

结论:
(1) 调度运行进程,本质就是让进程控制块task_struct进行排队!
(2) 再给进程下一个定义:进程 = 内核task_struct + 程序的代码和数据!

三,进程标识符:pid

我们先构建一个代码样例:
在这里插入图片描述

让它运行起来:
在这里插入图片描述

1.得到第一个结论:

./xxx 本质就是系统创建进程并运行

在这里插入图片描述

可以得到启示:

我自己写的代码相乘的可执行文件 == 系统命令。在linux系统中大部分执行的操作,本质就是运行进程。

在这里插入图片描述

2.每个进程都有自己的唯一标识符,叫做进程pid

1. 查看系统进程1: ps axj

先来查看当前系统中的进程信息:

使用指令:ps axj

在这里插入图片描述

这样查看的是所有的进程,很难帮助我们学习,现在我们根据上面的样例代码,所有进程中搜索我刚刚写的可执行程序:

使用指令:ps axj | grep myprocess

在这里插入图片描述
将进程信息的第一行打印出来:

使用指令: ps ajx | head -1

在这里插入图片描述

把上面进程中每行多列的含义进行对应起来:

使用指令:ps ajx | head -1 && ps axj | grep process

在这里插入图片描述

3.在Linux下使用指令终止进程
在我们的程序运行时,可以在运行的地方按CTRL+c来结束进程,但是还有一种方法可以结束进程:

使用指令: kill -9 要杀掉的进程id
(注:这里的-9是信号参数,直接使用即可)

2. 查看系统进程2: /proc

在Linux系统的根目录下,有一个动态文件proc,它里面存放着所有进程的信息,之所以叫动态文件是因为它会随着进程的改变而随时更新它的内容!
在这里插入图片描述

查看所有进程文件:

使用指令: ls /proc/

查看特点的进程文件:

使用指令: ls /proc/pid

我们每启动一个进程都会在proc文件目录下创建一个以该进程的pid为名称的文件夹。
在这里插入图片描述

可以发现,在自行创建的进程中有很多我们看不懂的文件,这些文件也不需要掌握,但是有两个文件需要大家注意,一个是cwd一个是exe:

在这里插入图片描述

1. exe指向可执行程序的位置:
进程的pcb中会记录自己对应的可执行文件的路径。
2. cwd代表当前文件:
进程的当前工作路径。

四,系统调用函数:getpid

每次查看进程使用都要使用ps指令,我感觉非常的麻烦,于是这里有一个系统调用函数可以直接返回当前进程的pid,由于操作系统是由C语言编写的,所以可以直接在程序中调用此函数:

使用函数: getpid()

使用man手册查看getpid相关信息:

在这里插入图片描述

使用方式:
在这里插入图片描述
在这里插入图片描述

五,父进程和子进程的概念

在使用ps指令查看进程详情时,除了pid我们可以看见左边还有一个ppid,这是parent pid的意思,也就是父进程的pid,请看下图:
在这里插入图片描述

再来学习一个可以查看父进程id的系统调用函数:
在这里插入图片描述

使用函数: getppid()

使用方式:
在这里插入图片描述
在这里插入图片描述

可以发现,每次运行时,子进程的id都在变化,然而父进程的id一直没变!这是因为在命令行中,父进程一般是命令行解释器: bash

在这里插入图片描述

六,创建子进程–fork函数的使用

Linux中创建进程的方式有两种:

1. 命令行中直接启动可执行程序
2. 通过代码创建进程

启动进程的本质就是创建进程,一般是通过父进程创建子进程,构成一种父子关系而命令行中启动的进程都是由bash为父进程模拟创建子进程的!

使用man指令查看fork函数信息:
在这里插入图片描述

1. 创建一个子进程并观察

写一个代码样例创建子进程观察情况:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2. fork返回值的理解

请大家自行使用man手册查看forh函数的返回值,这里把它翻译成中文:

在这里插入图片描述

理解下面的代码:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

首先,fork之后,父子进程都会执行代码的本质是它们都被内存调度了,而当一个函数执行到return时,它的核心工作才算执行完成,于是我们可以想象一下fork函数内部的一些代码信息:

在这里插入图片描述

在这里插入图片描述

3. 进程的独立性

在这里插入图片描述
在这里插入图片描述

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Python 基础学习笔记】文件的基础操作
  • cmake查看 编译信息里面的详细的gcc/g++的编译参数
  • 在Gin框架中实现Token令牌认证
  • CSS的盒子模型(Box Model)
  • 2024百度的组织架构和产品分布
  • SegFormer网络结构的学习和重构
  • LCR 029
  • [Web安全 网络安全]-CSRF跨站请求伪造
  • 面试经典 150 题:力扣88. 合并两个有序数组
  • 普通本科生也能成为AI高手:人工智能学习指南
  • 嵌入式 开发技巧和经验分享
  • 桌面专业版【修改主机名和更改计算机显示名称】方法介绍
  • Go语言Mutex的优化与TryLock机制解析
  • 微信小程序-使用vant组件库
  • 音视频入门基础:FLV专题(4)——使用flvAnalyser工具分析FLV文件
  • php的引用
  • hexo+github搭建个人博客
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • Apache的80端口被占用以及访问时报错403
  • es6
  • Js基础知识(一) - 变量
  • JWT究竟是什么呢?
  • Laravel Mix运行时关于es2015报错解决方案
  • node.js
  • PHP变量
  • php中curl和soap方式请求服务超时问题
  • 分享一份非常强势的Android面试题
  • 如何编写一个可升级的智能合约
  • 如何设计一个比特币钱包服务
  • 使用agvtool更改app version/build
  • 用mpvue开发微信小程序
  • 与 ConTeXt MkIV 官方文档的接驳
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • Mac 上flink的安装与启动
  • 组复制官方翻译九、Group Replication Technical Details
  • ​探讨元宇宙和VR虚拟现实之间的区别​
  • "无招胜有招"nbsp;史上最全的互…
  • # SpringBoot 如何让指定的Bean先加载
  • #HarmonyOS:Web组件的使用
  • $(function(){})与(function($){....})(jQuery)的区别
  • $.ajax,axios,fetch三种ajax请求的区别
  • (4) PIVOT 和 UPIVOT 的使用
  • (代码示例)使用setTimeout来延迟加载JS脚本文件
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (强烈推荐)移动端音视频从零到上手(下)
  • (十三)Flask之特殊装饰器详解
  • (五十)第 7 章 图(有向图的十字链表存储)
  • (一一四)第九章编程练习
  • (转)树状数组
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .NET Core 版本不支持的问题
  • .net 调用海康SDK以及常见的坑解释
  • .NET/C# 反射的的性能数据,以及高性能开发建议(反射获取 Attribute 和反射调用方法)