【Linux】12.Linux进程概念(1)

文章目录

  • 1. 冯诺依曼体系结构
  • 2. 操作系统(Operator System)
    • 概念
    • 设计OS的目的
    • 胆小的操作系统
    • 定位
    • 如何理解 "管理"
    • 总结
  • 3. 进程
    • 基本概念
    • task_struct-PCB的一种
    • task_ struct内容分类
    • 组织进程
    • 查看进程
    • 通过系统调用获取进程标示符
    • 通过系统调用创建进程-fork初识


1. 冯诺依曼体系结构

我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系。

9cb69cb2cf28cc8c5126f82f9cba886f

截至目前,我们所认识的计算机,都是有一个个的硬件组件组成

  • 输入单元:包括键盘, 鼠标,扫描仪, 写板等

  • 中央处理器(CPU):含有运算器和控制器等

  • 输出单元:显示器,打印机等

关于冯诺依曼,必须强调几点:

  • 这里的存储器指的是内存

  • 不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备)

  • 外设(输入或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取。

  • 一句话,所有设备都只能直接和内存打交道

  1. 存储器:内存

  2. 输入设备:鼠标,键盘,摄像头,话筒,磁盘,网卡…

  3. 输出设备:显示器,播放器硬件,磁盘,网卡…

有的设备是纯输入输出,也有的又是输入又是输出。

输入设备和输出设备统称为外设。

  1. 运算器:对我们的数据进行计算任务(算数运算,逻辑运算)
  2. 控制器:对我们的计算硬件流程进行一定的控制。

运算器和控制器统称为CPU

上面这些东西都是独立的个体,所以要用总线连接起来。

总线分为系统总线和IO总线。

存储是有效率的。寄存器最快,缓存其次,内存其次,外存最慢。


2. 操作系统(Operator System)

概念

任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:

  • 内核(进程管理,内存管理,文件管理,驱动管理)

  • 其他程序(例如函数库,shell程序等等)


设计OS的目的

与硬件交互,管理所有的软硬件资源(手段)

为用户程序(应用程序)提供一个良好的执行环境(目的)


胆小的操作系统

操作系统里面会有各种的数据,可是操作系统不信任任何用户。

操作系统为了保证自己数据安全,也为了保证给用户能够提供服务,操作系统以接口的方式给用户提供调用的入口,来获取操作系统内部的数据。

接口是操作系统提供的,用C实现的,自己内部的函数调用(系统调用)

所有访问操作系统的行为,都只能通过系统调用实现。


定位

在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件


如何理解 “管理”

管理的例子

描述被管理对象

组织被管理对象

a0d5390015d6b4219fdd963933684250

操作系统可以认为是决策者,驱动程序可以认为是执行者,软硬件资源可以认为是被管理者。

先描述,再组织

在操作系统中,管理任何对象,最终都可以转化为对某种数据结构的增删查改。

C/C++的库函数和系统调用之间的关系就是上下层的调用和被调用的关系。


总结

计算机管理硬件

  1. 描述起来,用struct结构体
  2. 组织起来,用链表或其他高效的数据结构

3. 进程

基本概念

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

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

描述进程-PCB

进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。

课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct

一个操作系统,不仅仅只能运行一个进程,还可以同时运行多个进程。

操作系统必须严格讲进程管理起来。

任何一个进程在加载到内存的时候,形成真正的进程时,操作系统要先创建描述进程属性的结构体对象PCB – 进程控制块。

可以认为PCB就是进程属性的集合,strut结构体里面存放的是进程编号,进程的状态,优先级…

进程 = 内核PCB的数据结构对象(描述你这个进程的所有的属性值) + 你自己的代码和数据


task_struct-PCB的一种

  • 在Linux中描述进程的结构体叫做task_struct。

  • task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。


task_ struct内容分类

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

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

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

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

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

  • 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。

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

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

  • 其他信息


组织进程

可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct链表的形式存在内核里。

在操作系统中,对进程进行管理,可以抽象为对一个个PCB连接起来的一个单链表的增删改查。

pcb -> task_struct结构体,里面包含进程的所有属性。

Linux中树如何组织进程,Linux内核中,最基本的组织进程task_struct的方式,采用双向链表组织的。


查看进程

进程的信息可以通过ps 或者 /proc 系统文件夹查看。

80fa53e2a692d0343cdebdae3c103e66

48f2ad6f3d639ca09b011cce8876fe06

简单写一个简单程序

6a96d659a2dbd4e07b36becc834dc939

我这里把这个进程杀掉,那个进程就自动死掉了。(这里的进程号和上面不同是因为我中间关掉了程序一次)

c7fa94819b0f36e48b0ade826b94dd80


通过系统调用获取进程标示符

  • 进程id(PID)

  • 父进程id(PPID)

proc.c

#include <stdio.h>
#include <unistd.h>int main(){while(1){printf("I am a process,my id is:%d\n",getpid());sleep(1);}return 0;
}

输入:

while : ; do ps ajx | head -1 ; ps ajx |grep proc |grep -v grep;echo"----------------------";sleep 1;done
# while : ; do ... done
# 创建一个无限循环
# : 是一个始终返回true的命令
# 会一直循环执行直到你按 Ctrl+C 停止# ps ajx | head -1                    # 显示进程列表的表头
# ps ajx | grep proc | grep -v grep   # 查找名为"proc"的进程(排除grep进程本身)
# echo "----------------------"        # 打印分隔行
# sleep 1                             # 暂停1秒

一开始没有运行程序,后来开启了进程。

833cf1c3283d242ac3fa42c892efa53d

然后改一下proc.c的代码

#include <stdio.h>
#include <unistd.h>int main(){while(1){printf("I am a process,my id is:%d,parent:%d\n",getpid(),getppid());sleep(1);}return 0;
}

里面的父进程和子进程的id也能对的上。

41fb3a0c665e4687de4e4c7e81ee89bc

这里每次子进程的pid都在变,但是父进程的ppid却不变。

aa534260085dda54a084529fe2d47e02

这个父进程是谁呢?

原来是bash

e5c791bd2dafe173ba677c373e94249e

这个bash在我们每次登录系统的时候,系统会默认分配一个bash进程给我们。


通过系统调用创建进程-fork初识

  • 运行 man fork 认识fork

  • fork有两个返回值

  • 父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main()
{printf("我是一个进程,pid:%d, ppid:%d\n",getpid(),getppid());pid_t id=fork();if(id==0){//子进程while(1){printf("我是子进程,pid:%d, ppid:%d\n",getpid(),getppid());sleep(1);}}else if(id>0){//父进程while(1){printf("我是父进程,pid:%d, ppid:%d\n",getpid(),getppid());sleep(1);}}else{//error}return 0;
}

这里面出现了我是子进程我是父进程,说明fork返回了两个值,简直是匪夷所思啊,以前的函数明明只能返回一个值的。

这里说明,fork又创建了一个进程,并且出现了父进程和子进程的死循环。

一开始这个程序是只有一个进程的,后来多出来一个子进程,形成了一个分支。

29a9c8c448252ed53e3c1a91dfa8564a

  1. 为什么fork要返回两个值?给父进程返回子进程的pid,给子进程返回0呢?

    返回不同的返回值,是为了区分,让不同的执行流,执行不同的代码块。

  2. 一个函数是如何做到返回两次的?如何理解?

    fork也是个函数,当一个函数到了return语句的时候,他应该执行的核心工作已经实现完了。

    return语句也是代码,是被父子进程所共享的,所以父进程的return执行好了 会执行子进程的return

  1. fork函数究竟在干什么?干了什么?

进程=内核数据结构+代码和数据

一开始只有一个进程,也就是父进程,他有它对应的数据和代码。

然后新创建了一个子进程,子进程刚被创建出来的时候,是没有对应的代码和数据的,所以会指向父进程对应的代码。

所以fork之后,父子进程的代码是共享的。

f1ef3f05f01b96d50d2d229951835562

但我们创建子进程肯定是想让子进程完成和父进程不一样的事情,所以我们要想办法让父和子进程执行不同的代码块。

这就让fork有了不同的返回值。

  1. 一个变量为什么会有不同的内容?如何理解?

在任何平台,进程在运行的时候,是具有独立性的。我一个进程崩了不会影响其他的进程。

上面讲到,子进程会和父进程共用代码块,但是子进程没有数据,只能也死皮赖脸的从父进程拷贝一个数据,这个操作是操作系统自动完成的。

于是,两个进程的数据独立,代码公共,自然可以返回两个不同的内容了。

当然上面只是我们期望的,实际上子进程直接拷贝父进程的数据会导致数据太冗余了。

所以操作系统在子进程要对父进程的数据进行修改的时候,要改哪段,就会申请哪段的数据,可以称为数据层面的写时拷贝。

当子进程不修改父进程数据时,会采用写时父进程的数据和代码。

b75b3d4eed4f364034b0e1c0e38c2695

  1. 父子进程创建好后,fork先运行父进程还是子进程?

    不确定,谁先运行由调度器确定。

    调度器:选择运行哪个进程。(尽可能地平均和公平)

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

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

相关文章

【Linux网络编程】序列化与反序列化

目录 一&#xff0c;序列化和反序列化的说明 二&#xff0c;Jsoncpp库的介绍 三&#xff0c;Jsoncpp库的使用 3-1&#xff0c;Json::Value类 3-2&#xff0c;Json::StreamWriter类 3-3&#xff0c;Json::CharReader类 一&#xff0c;序列化和反序列化的说明 序列化与反…

Oracle报错ORA-01078、LRM-00109

虚拟机异常关机后&#xff0c;rac数据库备机无法启动数据库&#xff0c;报错如下 解决方法&#xff1a; 找到如下路径文件 执行&#xff1a; cp init.ora.016202516818 /u01/app/oracle/product/19.3.0/db/dbs/ mv init.ora.016202516818 initplm2.ora 再次进入命令行sqlpl…

STM32-keil安装时遇到的一些问题以及解决方案

前言&#xff1a; 本人项目需要使用到STM32,故需配置keil 5&#xff0c;在配置时遇到了以下问题&#xff0c;并找到相应的解决方案&#xff0c;希望能够为遇到相同问题的道友提供一些解决思路 1、提示缺少&#xff08;missing&#xff09;version 5编译器 step1&#xff1a;找…

【Hive】海量数据存储利器之Hive库原理初探

文章目录 一、背景二、数据仓库2.1 数据仓库概念2.2 数据仓库分层架构2.2.1 数仓分层思想和标准2.2.2 阿里巴巴数仓3层架构2.2.3 ETL和ELT2.2.4 为什么要分层 2.3 数据仓库特征2.3.1 面向主题性2.3.2 集成性2.3.3 非易失性2.3.4 时变性 三、hive库3.1 hive概述3.2 hive架构3.2.…

mqtt详细介绍及集成到springboot

mqtt详细介绍及集成到springboot 1.mqtt发布/订阅消息参数详细介绍2. mqtt客户端连接参数介绍3. docker-compose搭建mqtt服务端4. springboot集成mqtt实现发布订阅5. 测试注意事项 1.mqtt发布/订阅消息参数详细介绍 1.1. qosQoS0 &#xff0c;Sender 发送的一条消息&#xff0…

基于springboot的租房网站系统

作者&#xff1a;学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等 文末获取“源码数据库万字文档PPT”&#xff0c;支持远程部署调试、运行安装。 项目包含&#xff1a; 完整源码数据库功能演示视频万字文档PPT 项目编码&#xff1…

自动化办公|xlwings简介

xlwings 是一个开源的 Python 库&#xff0c;旨在实现 Python 与 Microsoft Excel 的无缝集成。它允许用户使用 Python 脚本自动化 Excel 操作&#xff0c;读取和写入数据&#xff0c;执行宏&#xff0c;甚至调用 VBA 脚本。这使得数据分析、报告生成和其他与 Excel 相关的任务…

概率函数,累计分布函数

四. 累计分布函数 1. 累计分布函数&#xff08;CDF, Cumulative Distribution Function&#xff09; 累计分布函数是用来描述随机变量取值小于或等于某个给定值的概率。它适用于离散型和连续型随机变量&#xff0c;并且能够通过概率质量函数&#xff08;PMF&#xff09;或概率…

Flutter项目适配鸿蒙

Flutter项目适配鸿蒙 前言Flutter项目适配鸿蒙新工程直接支持ohos构建新项目编译运行 适配已有的Flutter项目 前言 目前市面上使用Flutter技术站的app不在少数&#xff0c;对于Flutter的项目&#xff0c;可能更多的是想直接兼容Harmonyos&#xff0c;而不是直接在重新开发一个…

链家房价数据爬虫和机器学习数据可视化预测

完整源码项目包获取→点击文章末尾名片&#xff01;

【20250113】基于肌肉形变测量的连续步态相位估计算法,可自适应步行速度和地形坡度...

【基本信息】 论文标题&#xff1a;Continuous Gait Phase Estimation by Muscle Deformations with Speed and Ramp Adaptability 发表期刊&#xff1a;IEEE Sensors Journal 发表时间&#xff1a;2024年5月30日 【访问链接】 论文链接&#xff1a;https://ieeexplore.ieee.or…

【全套】基于分类算法的学业警示预测信息管理系统

【全套】基于分类算法的学业警示预测信息管理系统 【摘 要】 随着网络技术的发展基于分类算法的学业警示预测信息管理系统是一种新的管理方式&#xff0c;同时也是现代学业预测信息管理的基础&#xff0c;利用互联网的时代与实际情况相结合来改变过去传统的学业预测信息管理中…

小程序组件 —— 31 事件系统 - 事件绑定和事件对象

小程序中绑定事件和网页开发中绑定事件几乎一致&#xff0c;只不过在小程序不能通过 on 的方式绑定事件&#xff0c;也没有 click 等事件&#xff0c;小程序中绑定事件使用 bind 方法&#xff0c;click 事件也需要使用 tap 事件来进行代替&#xff0c;绑定事件的方式有两种&…

邮箱发送验证码(nodemailer)

邮箱发送验证码 打开SMTP 服务使用 Node.js 邮件发送模块&#xff08;nodemailer&#xff09;封装验证码组件 开发中经常会遇到需要验证码&#xff0c;不过手机验证码需要money&#xff0c;不到必要就不必花费&#xff0c;所以可以使用邮箱发送验证码 打开SMTP 服务 根据自己想…

AV1视频编解码简介、码流结构(OBU)

我的音视频/流媒体开源项目(github) 目录 一、AV1编码技术 二、AV1码流结构(OBU) 三、IVF文件格式 四、ffmpeg支持AV1 五、关于常见格式对AV1的封装 一、AV1编码技术 AV1是由开放媒体联盟(AOM&#xff0c;Alliance for Open Media)在2018年发布的&#xff0c;AV1的前身…

Sentaurus TCAD学习笔记:transform指令

目录 一、transform指令简介二、transform指令的实现1.cut指令2.flip指令3.rotate指令4.stretch指令5.translate指令6.reflect指令 三、transform指令示例 一、transform指令简介 在Sentaurus中&#xff0c;如果需要对器件进行翻转、平移等操作&#xff0c;可以通过transform指…

kafka消费堆积问题探索

背景 我们的商城项目用PHP写的&#xff0c;原本写日志方案用的是PHP的方案&#xff0c;但是&#xff0c;这个方案导致资源消耗一直降不下来&#xff0c;使用了20个CPU。后面考虑使用通过kafka的方案写日志&#xff0c;商城中把产生的日志丢到kafka中&#xff0c;在以go写的项目…

【opencv】第7章 图像变换

7.1 基 于OpenCV 的 边 缘 检 测 本节中&#xff0c;我们将一起学习OpenCV 中边缘检测的各种算子和滤波器——Canny 算子、Sobel 算 子 、Laplacian 算子以及Scharr 滤波器。 7.1.1 边缘检测的一般步骤 在具体介绍之前&#xff0c;先来一起看看边缘检测的一般步骤。 1.【第…

[Qt]常用控件介绍-多元素控件-QListWidget、QTableWidget、QQTreeWidget

目录 1.多元素控件介绍 2.ListWidget控件 属性 核心方法 核心信号 细节 Demo&#xff1a;编辑日程 3.TableWidget控件 核心方法 QTableWidgetItem核心信号 QTableWidgetItem核心方法 细节 Demo&#xff1a;编辑学生信息 4.TreeWidget控件 核心方法 核心信号…

[Linux]从零开始的STM32MP157交叉编译环境配置

一、前言 最近该忙的事情也是都忙完了&#xff0c;也是可以开始好好的学习一下Linux了。之前九月份的时候就想入手一块Linux的开发板用来学习Linux底层开发。之前在NXP和STM32MP系列之间犹豫&#xff0c;思来想去还是入手了一块STM32MP157。当然不是单纯因为MP157的性能在NXP之…