【Linux】从零开始认识进程 — 前篇

news2024/11/19 6:25:30

在这里插入图片描述
我从来不相信什么懒洋洋的自由。我向往的自由是通过勤奋和努力实现的更广阔的人生。。——山本耀司

从零开始认识进程

  • 1 认识冯诺依曼体系
  • 2 操作系统
  • 3 进程
    • 3.1 什么是进程???
    • 3.2 进程管理
      • PCB
    • 3.3 Linux中的进程
      • 深入理解
    • 3.4 进程创建
    • 总结
  • 送给大家一句话:
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

1 认识冯诺依曼体系

学习进程,我们需要对计算机操作系统 有一个初步的了解,也就是经典的冯诺依曼体系:
计算机的逻辑结构。冯·诺依曼从逻辑入手,他的逻辑设计具有以下特点:
(1)将电路、逻辑两种设计进行分离,给计算机建立创造最佳条件;
(2)将个人神经系统、计算机结合在一起,提出全新理念,即生物计算机。
符合人们的一般认知:
在这里插入图片描述
我们所认识的计算机,都是有一个个的硬件组件组成

  1. 输入单元:包括键盘, 鼠标,扫描仪, 写板等
  2. 中央处理器(CPU):含有运算器和控制器等
  3. 输出单元:显示器,打印机等

关于冯诺依曼体系结构,必须强调几点:

  1. 这里的存储器指的是内存
  2. 不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备)外设(输入或输出设备)
  3. 要输入或者输出数据,也只能写入内存或者从内存中读取。
  4. 一句话,所有设备都只能直接和内存打交道。

对冯诺依曼的理解,不能停留在概念上,要深入到对软件数据流理解上

了解冯诺依曼体系结构,接下来我们来认识操作系统

2 操作系统

操作系统可以理解为硬件和用户层面之间的一个软件。让用户通过操作系统可以来对硬件进行访问。那为什么不让用户直接操作硬件呢?打个比方:
我们把银行抽象为一台电脑,银行的金库是我们的硬盘,而我们想要去银行取钱或存钱(获取数据/存入数据),那你说如果我们每个人都可以进入到金库自行行动,(相信大家都是有道德感的人,会如实操作),但群众中里肯定有坏人,假如他存1000元,却报告存了10000元,那银行系统就要崩溃了。所以才会有银行柜台(相当于操作系统提供的接口)让我们可以正常进行操作,不会发生恶性事件

操作系统是必然存在的在整个计算机软硬件架构中,操作系统的定位是: 一款纯正的“搞管理”的软件
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:
内核(进程管理,内存管理,文件管理,驱动管理)其他程序(例如函数库, shell程序等等

设计OS的目的:

  1. 与硬件交互,管理所有的软硬件资源
  2. 为用户程序(应用程序)提供一个良好的执行环境

这里通过一个图示,供大家学习使用:

在这里插入图片描述
系统调用和库函数概念:

  1. 在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用。
  2. 系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者可以对部分系统调用进行适度封装,从而形成库(lib),有了库,就很有利于更上层用户或者开发者进行二次开发。

这里也可以解释为什么有些代码不具有跨平台性了:
因为直接访问的操作系统的调用接口与平台紧密相关。平台不同(操作系统不同)那系统调用接口,返回值等大概率不同,所以不具有跨平台性
c/c++ 具有跨平台性

接下来我们来学习进程!

3 进程

3.1 什么是进程???

相信大家一定对这个词充满陌生(不管你陌不陌生,反正我第一眼看是不理解什么是进程,太抽象了),但实际上,我们每天都在接触进程(除非你不玩手机,不用电脑)。那我们就俩看看电脑的进程是怎样的吧:
非常简单,我们打开任任务管理器,看见的都是正在进行的进程
在这里插入图片描述
这都是正在进行的进程,所以进程并不高深,是十分常见。
基本概念:

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

我们也同任务管理器看到,进程是可以同时存在非常多的

3.2 进程管理

我们知道了进程是什么,那接下来我们来聊聊进程是如何进行管理的吧

进程是通过PCB来进行描述和管理的
进程 = PCB + 自己的数据和代码

PCB

PCB 实质上是一种结构体,里面包含该进程的信息,和下一进程的地址:类似如下结构

struct PCB{
	//所有属性
	//指向下一个进程
	struct PCB* next;
	//内存指针
	//储存对应数据,代码等
	//....
}

一个进程一定要有一个PCB。

那为什么要有PCB呢???:因为操作系统(os)要对进程进行管理!!!

3.3 Linux中的进程

每个操作系统都有自己对应的PCB模块,那我们来看一下linux 的PCB是什么样子:

struct task_struct{
	//Liunx 进程控制模块  
}

在linux里,通过链表进行的PCB管理 ,同时使用队列里选择任务进行运算。即:

  1. 在队列里取出任务
  2. 找到任务对应的PCB
  3. 通过PCB调用对应数据进行CPU运算。

调度运行进程,本质就是让进程控制块task_struct进行排队!!!

在根据进程的概念我们可以理解linux的进程为:
进程 = 内核task_ struct结构体 + 程序的代码和数据

深入理解

现在我们来进入到linux中来看看进程的Task_struct本身内部的属性都有哪些???
现在,linux 启动!!!
在这里插入图片描述
. / 的本质就是让系统创建进程并运行 (此外每个指令也是一个可执行程序)
我们自己写的代码形成的可执行程序 == 系统命令 == 可执行程序。
在Linux 中大部分的执行操作本质都是运行进程!!!

现在我们再来看看Linux中的“任务管理器”,让我们一起来看看然后才能查看进程
ps ajx 可以查看我们的进程,为了方便演示我们使用grep 来进行一下筛选:
ps ajx | grep myprogress
在这里插入图片描述在下面的 grep -…也是我们的进程,因为每次grep查找 都会形成进程 因而就会出现两个进程。
接下来我们来认识一下具体属性:
我们使用ps ajx | head -1(即只打印第一行)
在这里插入图片描述
然后怎么查看对应信息呢???光看到这一行也无法理解
使用指令 && 指令 即可:
在这里插入图片描述
这样我们成功打印出来进程信息,我们来认识一下:

  1. PID : 每一个进程都要有自己的唯一标识符,叫做进程PID

那么我们能不能通过可执行程序自己查到我们的PID呢?(这样就省去ps命令了)。
当然可以!!!
pid 储存在 struct task_struct 中,而struct task_struct 是内核数据结构,用户不能轻易访问(上面有讲到为什么不能访问),那么如何才能获取呢???当然是使用系统提供给我们的接口了
pid_t getpid() 就是这样的接口。我们把接口加入到我们的代码中试试。
(getppid () 是返回父进程 )
在这里插入图片描述
我们验证一下,PID是否正确:
在这里插入图片描述
显然 pid 的打印是正确的!!!

我们可以成功进行进程了,那么有没有方法可以结束进程呢???
当然有了!
kill -9 pid 就可以干掉想要结束的进程了,(kill是不是非常霸气!!!,起码把微软的结束进程霸气多了)
我们来尝试一下:可以看到我们成功kill 掉了正在进行的进程!
在这里插入图片描述
记住:

  1. Ctrl + C 就是在用户层面终止进程,kill -9 pid 可以用来直接杀掉进程!!!

3.4 进程创建

首先来解释一下父进程,ppid 是父进程的ID
pid_t getppid()返回父进程的ID,而子进程是由父进程创建的,这里只做了解。
下面演示一下如何获取父进程的ID:
在这里插入图片描述
这样我们就获取到了父进程ID。
当我们多次运行时,每次进程PID都是不同的,但是父进程ID是相同的(每次运行 PID 不同是正常的)

那我们追溯一下这个父进程到底是谁
同样使用grep差找到该进程
在这里插入图片描述
可以看到的 父进程是bash,什么是bash???可以先理解为命令行解释器。目前还没有深入探讨的能力

接下来我们来尝试是否可以手动实现创建子进程
首先来认识一下 fork函数
fork() (可以通过运行 man fork 认识fork)

  • fork有两个返回值
  • 父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)
  • 创建一个进程,本质是系统中多一个进程,多一个进程,就是多一个内核task_struct
  • 父进程的代码和数据是从磁盘加载来的,子进程的代码和数据会默认进程父进程的代码和数据

为什么要创建子进程呢:因为我们想要通过子进程与父进程执行不一样的代码,在特殊情况下可以提高运行效率。

接下来我们来认识一下fork()函数的返回值,因为他两个返回值(与以往的认识函数不一样)。

  1 #include<stdio.h>  
  2 #include<unistd.h>  
  3 #include<sys/types.h>  
  4   
  5 int main(){  
  6   
  7   printf("process is running ,only me! pid: %d \n",getpid() );  
  8   fork();  
  9   pid_t id = fork();  
 10   
 11   if(id == -1) return 1;  
 12   else if(id == 0){  
 13     //child  
 14     while(1)  
 15     {   
 16       printf("id : %d I am child process,pid: %d, ppid: %d\n",id,getpid(),getppid());         
 17       sleep(1);                    
 18                                    
 19     }                              
 20   }                                
 21   else{                            
 22     //parent                       
 23     while(1){                                               
 25       printf("id : %d I am parent process,pid: %d, ppid: %d\n",id,getpid(),getppid());  
 26       sleep(2);                    
 27     }                              
 28                                    
 29   }                                
 30                                                 
 31   } 

简单写一下测试程序,来看效果:
可以看出是成功运行出子进程和父进程
在这里插入图片描述
刚才的代码,在9 行 fork()之后,子进程和父进程是共享的,因为我们进行了判断,所以子进程与父进程会执行不一样的代码,在之前学习的语法中,if 与 else 的代码不可能一起运行,这是因为之前学习的都是单进程,在多进程中可以做到,即使这样,那也也有很多疑问:

  1. 同一个 id 为什么可以即等于零 又 不等于于零???
  2. fork()两个返回值是怎么回事???

问题1 涉及虚拟地址空间,我目前还没有了解。

那我们来看fork函数(由OS提供),在代码执行的过程中,子进程就已经存在了,可以被调度了。

在任何操作系统中,进程一定要做到:进程具有独立性 ,PCB = 内核数据结构task_struct +代码与数据(只读
那么如何查看该进程使用了哪些数据和代码呢???
使用ls /proc/pid -d就可以查到该进程的数据:
在这里插入图片描述
我们详细展开即可查看:
在这里插入图片描述
其中的exe 指向 是从什么路径下的文件加载的可执行程序。
在进程结束之后对应路径也会被销毁。

总结

  1. 进程 = 内核task_ struct结构体 + 程序的代码和数据
  2. ps ajx 可以查看我们的进程,为了方便演示我们使用grep 来进行一下筛选:ps ajx | grep myprogress
  3. PID : 每一个进程都要有自己的唯一标识符,叫做进程PID
  4. pid_t getpid() 获取pid
  5. 当我们多次运行时,每次进程PID都是不同的,但是父进程ID是相同的(每次运行 PID 不同是正常的)
  6. fork() 有两个返回值,父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝),创建一个进程,本质是系统中多一个进程,多一个进程,就是多一个内核task_struct ,父进程的代码和数据是从磁盘加载来的,子进程的代码和数据会默认进程父进程的代码和数据

送给大家一句话:

我从来不相信什么懒洋洋的自由。我向往的自由是通过勤奋和努力实现的更广阔的人生。。——山本耀司

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1521357.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【vue baidu-map】实现百度地图展示基地,鼠标悬浮标注点展示详细信息

实现效果如下&#xff1a; 自用代码记录 <template><div class"map" style"position: relative;"><baidu-mapid"bjmap":scroll-wheel-zoom"true":auto-resize"true"ready"handler"><bm-mar…

JVMJava虚拟机

JVM的内存区域 程序计数器&#xff1a; 字节码解释器通过改变程序计数器来依次读取指令&#xff0c;从而实现代码的流程控制&#xff0c;如&#xff1a;顺序执行、选择、循环、异常处理。 在多线程的情况下&#xff0c;程序计数器用于记录当前线程执行的位置&#xff0c;从而当…

python—gui-计算图像像素两点间距离

代码&#xff1a; import tkinter as tk from tkinter import ttkdef create_gui():# 创建Tkinter窗口root tk.Tk()# 设置窗口标题root.title("显示图片")# 图片文件路径image_path path_to_your_image.jpg# 加载图片img load_image(image_path)# 创建标签&#…

产品推荐 - ALINX XILINX FPGA开发板 Artix-7 XC7A100T-2FGG484I

01开发板介绍 此款开发板采用核心板扩展板的模式&#xff0c;方便用户对核心板的二次开发利用。FPGA使用的是Xilinx公司的ARTIX-7系列的芯片&#xff0c;型号为XC7A100T-2FGG484I。在核心板使用了2片MICRON公司的MT41J256M16HA-125 DDR3芯片&#xff0c;组合成32bit的数据总线…

联想拯救者刃7000K2024游戏电脑主机仅售6999元

这款联想拯救者刀锋7000K 2024游戏电脑主机在京东促销中售价仅为6999元&#xff0c;相比原价7499元有相当大的折扣。 这是一款功能强大的游戏电脑&#xff0c;配备了全新的 15-14400(F) 处理器和 RTX™ 4060 显卡&#xff0c;以及 16GB DDR5 内存和 1TB 固态硬盘。 外观方面&a…

STL_vector简化模拟—详解深层次深拷贝问题

文章目录 迭代器框架和成员变量基础成员函数容量相关的成员函数关于深拷贝中的深拷贝问题operator[ ]重载和内容修改函数类模板内的嵌套类型全部代码 根据原码看出vector的成员并不像string类的一个指针加一个size和一个capacity。 而是三个指针&#xff0c;_start , _finish ,…

IntelliJ IDEA 面试题及答案整理,最新面试题

IntelliJ IDEA中的插件系统如何工作&#xff1f; IntelliJ IDEA的插件系统工作原理如下&#xff1a; 1、插件架构&#xff1a; IntelliJ IDEA通过插件架构扩展其功能&#xff0c;插件可以添加新的功能或修改现有功能。 2、安装和管理&#xff1a; 通过IDEA内置的插件市场下载…

【海贼王的数据航海】排序——直接选择排序|堆排序

目录 1 -> 选择排序 1.1 -> 基本思想 1.2 -> 直接选择排序 1.2.1 -> 代码实现 1.3 -> 堆排序 1.3.1 -> 代码实现 1 -> 选择排序 1.1 -> 基本思想 每一次从待排序的数据元素中选出最小(或最大)的一个元素&#xff0c;存放在序列的起始位置&…

springCloudeAlibaba的使用

父pom文件&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.o…

【Docker篇】数据卷相关操作

文章目录 &#x1f388;前言&#x1f354;数据卷&#x1f6f8;操作命令⭐创建一个数据卷&#xff0c;并查看数据卷在宿主机的目录位置 &#x1f339;挂载数据卷 &#x1f388;前言 在前面文章的nginx案例中&#xff0c;修改nginx的html页面时&#xff0c;需要进入nginx内部。并…

k8s-高可用etcd集群 26

reset掉k8s2&#xff0c;k8s3&#xff0c;k8s4节点 清理完网络插件后重启 快速创建一个k8s集群 修改初始化文件 添加master节点 备份 查看etcd配置 启动docker 将etcd二进制命令从容器拷贝到本机 备份 查看快照状态 删除集群资源 恢复 停掉所有的核心组件 从快照恢复 重启所有…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:StepperItem)

用作Stepper组件的页面子组件。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 支持单个子组件。 接口 StepperItem() 属性 参数名参数类型参数描述prevLabelstring设置左侧文本按钮内…

python 统计中国观鸟记录中心官网已观测的鸟类种类

python 统计中国观鸟记录中心官网已观测的鸟类种类 中国观鸟记录中心网站&#xff1a;https://www.birdreport.cn/ 先下载官网 Excel 文件 文件放置目录如下&#xff1a; home dataset xxx.xlsxxxx.xlsxxxx.xlsx Excelgrep.py &#xff08;进行文件内容提取的程序&#xff…

day-21 前 K 个高频元素

思路&#xff1a;用ans[]存储频次最高的k个元素&#xff0c;用anslen[]存储对应的索引&#xff0c;将nums进行排序依次统计每个元素出现次数&#xff0c;再判断是否需要对ans[]和anslen[]进行替换&#xff0c;最后ans即为答案 注意点&#xff1a;遍历结束后&#xff0c;还需要…

数据库引论:2.SQL简介

SQL(Structured Query Language,结构化查询语言) 2.1 SQL查询语言概览 SQL语言包含 数据定义语言(Data-Definition Language,DDL)。SQL DDL提供定义关系模式、删除关系以及修改关系模式的命令。数据操纵语言(Data-Manipulation Language,DML)。SQL DML提供从数据库中查询信息…

【算法】AC自动机的优化:增量更新与删除

一、概述 AC自动机&#xff08;Aho-Corasick Automation&#xff09;是著名的多模匹配算法&#xff0c;源于贝尔实验室&#xff0c;并且在实际应用中得到广泛的引用&#xff0c;且具有以下特点&#xff1a; 只需要扫描一次文本&#xff0c;即可获取所有匹配该文本的模式串复杂…

小红书根据关键词取商品列表 API 返回值说明

小红书根据关键词取商品列表的API返回值通常包含与搜索请求相关的商品列表信息。这些信息包括匹配到的商品列表、商品详情、排序方式等。以下是一个简化的示例&#xff0c;展示了小红书根据关键词取商品列表API可能返回的JSON格式数据&#xff1a;获取调用详情链接 item_searc…

王道机试C++第8章递归与分治 Day35和蓝桥杯两道真题程序

第 8 章 递归与分治 递归是指&#xff1a;函数直接或间接调用自身的一种方法&#xff0c;通常可把一个复杂的大型问题层层转化为与原问题相似但规模较小的问题来求解。 递归策略只需少量的程序就可描述解题过程所需的多次重复计算&#xff0c;因此大大减少了程序的代码量。 8.…

一个命令查看自己的WIFI密码

一个命令查看自己的WIFI密码 忘记wifi密码怎么办&#xff1f;一个命令查看自己的wifi密码。 一、打开命令行 使用快捷键“WinR”&#xff0c;打开运行窗口&#xff0c;输入“cmd”后回车即可。 二、输入命令network shell命令 输入命令network shell&#xff0c;简称netsh&…

Android 面试题及答案整理,最新面试题

Android中Intent的作用及分类 Intent在Android中用作组件之间传递信息&#xff0c;它可以用于启动活动(activity)、服务(service)和发送广播(broadcast)。Intent主要分为显式Intent和隐式Intent两大类。 1、显式Intent&#xff1a; 直接指定了要启动的组件名称&#xff08;比如…