进程概念理解

news2024/12/27 15:39:13

既然要了解计算机的进程,那么就需要先了解一下计算机的底层结构

目录

冯洛伊曼体系结构

操作系统 

系统调用接口

进程

PCB

task_struct 内容

操作系统如何组织进程


冯洛伊曼体系结构

想了解计算机的底层结构,那么必定绕不开冯洛伊曼体系结构;

作为计算机的基本构成,冯洛伊曼结构大概如下图:

 不过需要注意的是,此处的存储器并非指的硬盘,而是单纯指的内存

硬盘属于外设,既能够输入数据到设备中,也能够输出数据到硬盘中,并非是存储器;

其中运算器+控制器就是CPU,也就是中央处理器,用来处理数据和代码;

根据冯洛伊曼体系结构,我们能够发现

不管是输入设备还是输出设备,亦或是中央处理器;

它们之间工作都必须经过存储器,也就是内存才能够进行数据的交换;

这是为什么呢?

1.CPU是最快的设备,内存速度仅次于CPU,而外设的速度最慢;

2.若是直接让CPU和外设交换数据,那么外设就会拖慢CPU的速度;

3.内存作为中间设备,能够提高工作效率;

这时就有一个问题了——既然内存既能够存储数据,速度又快,那为什么不直接用内存存储数据而抛弃硬盘这种外设呢?

这就设计到内存的特点了——断电易失;

和硬盘不同的是,内存只能够做临时存储,当电源断开的时候,内部的数据就会全部丢失;

硬盘能够做到永久存储,因此只能够使用硬盘来存储数据,让硬盘和内存配合工作;

结论:

1.在数据层面上,CPU不和外设交互,只和内存进行交互;

2.当外设的数据需要载入,必须先将数据载入到内存中去,再由内存载入到CPU中;

3.CPU想要将数据写入到外设中,也必须先载入到内存中去;

操作系统 

了解了计算机的硬件结构之后,我们需要再来了解一下软件层面的操作系统;

操作系统是一种管理软硬件资源的软件,其目的是通过合理管理软硬件资源,来给用户提供良好的执行环境;

那么操作系统是如何做到管理软硬件资源的呢?

我们先来看下面的图:

 我们发现,在操作系统和底层硬件之间,还有一层软件——驱动程序;

而每种硬件都有对应的驱动;

而操作系统就是通过驱动来获取硬件的数据;

并且通过驱动来对硬件进行管理;

现在我们知道了操作系统是通过驱动来管理底层的硬件;

但是操作系统究竟是如何做的呢?

这就要说到管理的本质了;

管理的本质——先描述,再组织;

操作系统将每一种硬件设备抽象成一种结构体;

这个结构体内部成员有表示硬件类型的成员,有表示硬件状态的成员;

 操作系统将硬件描述成统一的结构体之后;(先描述)

使用链表或者其他的一些数据结构来将这些结构体对象组织起来;(再组织)

通过这样的操作,操作系统就从对硬件的管理转换为对结构体对象的管理

每一个结构体对象都对应了对应的硬件,通过驱动来不断获取对应硬件的数据并更新数据;

而操作系统是能够管理软硬件资源的,它对软件管理方式和对硬件管理也是一样的;

将软件描述成结构体后,再用数据结构组织起来;

系统调用接口

经过上面的解释,我们可以初步了解操作系统;

而因为操作系统过于复杂,不能让用户随意更改,所以它不会暴露自己的全部接口;

对于用户来说,操作系统只会暴露一部分接口,供用户使用;

这就是所谓的系统调用接口;

但是系统调用接口的使用难度较高,因此开发者们对部分系统调用接口进行了包装;

也就是所谓的库,利于开发者们进行开发;

而我们想要了解的进程就是由操作系统管理的,也是通过先描述,再组织的方法来管理的

进程

:加载到内存中的程序

进程就是一种加载到内存中的程序,而进程的信息都被放在一个叫做进程控制块的数据结构中;

也就是PCB;

PCB

这里我们用PCB的一种——task_struct 来解释;

task_struct 是linux中用来描述进程的结构体;

它将进程抽象成一个结构体,有各种各样的内容:

task_struct 内容

1.标识符:用来区别其他进程

2.状态:任务状态,退出码,退出信号等

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

4.程序计数器:程序中将被执行的下一条指令的地址

5.内存指针:包括程序代码和进程相关数据的指针,以及其他进程共享的内存块的指针

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

7.I/O状态信息:包括各种各样的I/O请求,分配给进程的I/O设备等

8.记账信息:包括处理器时间总和等

9.其他信息

了解了 task_struct 的内容后,那么操作系统是怎么组织进程的呢?

操作系统如何组织进程

我们先来看一张图

 当磁盘中的程序被加载到内存中,操作系统会创建一个对应的 task_struct 对象来与该程序关联

若是有多个程序被加载到内存后,操作系统会用链表的方式将 task_struct 对象们组织起来

然后操作系统再根据 task_struct 对象的优先级来将对应的程序加载到 CPU 中;

若是需要结束某个进程,也只是需要找到对应进程的 task_struct 对象,释放对应的程序后,

删除该 task_struct 对象就行;

这样就将对程序的管理转换为对 task_struct 对象的管理了;

查看进程

ps axj | grep <对应程序名>

#include<stdio.h>
#include<unistd.h>
int main()
{
        while(1)
        {
                printf("I am process!\n");
                sleep(1);
        }
        return 0;
}

 (以上代码在xshell中进行)

 我们在代码中写下一个死循环,来输出一句话;

 

 接着输入 "ps axj " 的指令来查看对应的进程;

简单解释一下我所输入的指令;

ps axj 表示查询进程,而它  ' | ' 上 "head -1" 表示带上对应数据的标题;

而 "grep myprocess" 表示我所需要查询的进程是哪个;

而 "ps axj | head -1" && 上 "ps axj | grep myprocess | grep -v grep"则表示这两个查询同时进行;   

而 "grep -v grep " 则是因为 grep 本身也是一个进程,这句话表示不用查询 grep 进程

 ls /proc/<进程对应的pid>

除了ps axj 以外,还有一种方式查看进程,而 pid 则是对应文件的标示符;

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

此处我使用 getpid() 来获取该进程的文件标示符;

 通过 ls /proc/<pid> 的命令,我们能够进入到对应进程所在目录(在linux下,进程也能用目录表示),看到进程的所有内容;

而我们的 proc 实际上是一种内存级的目录,用来管理 linux 下所有的进程;

通过系统调用接口获取文件标示符

上面的 getpid 指的是获取本进程的文件标示符,而 ppid 则是本进程的父进程的文件标示符;

而通过 pid ,我们可以使用各种指令来操作该进程,比如 kill 指令;

 

 kill 指令有各种操作, kill -9  <pid >表示杀死某个进程;

 而这里的父进程的pid一般是不会该改变的;

接下来我们写这样的代码:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
        while(1)
        {
                printf("I am process!my pid = %d,ppid = %d   \n",getpid(),getppid());
                sleep(1);
        }
        return 0;
}

然后重复运行; 

 我们发现,pid 每次都改变了,但是 ppid 并没有变化;

那么这里的 ppid 是什么进程??

我们发现,ppid 的进程是 -bash,也就是 shell 中的命令行解释器;

若是我们 kill 了bash会怎么样?

 kill 之后,我们就需要重新登录 shell 了;

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

 

 fork 就是单纯的创建一个子进程,但是它的返回值却不同;

fork 的返回值对于子进程来说,会返回 0 给子进程;

而对于父进程来说,fork 会返回子进程的 pid 给父进程;

若是创建失败,则返回-1给父进程,不会创建子进程;

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
        pid_t  id = fork();
        if(id == 0)
        {
                printf("I am child process!my pid = %d,ppid = %d id = %d\n",getpid(),getppid(),id);
        }
        else
        {
                printf("I am parent process!my pid = %d,ppid = %d id = %d\n",getpid(),getppid(),id);
        }
        return 0;
}

 我们发现,确实给返回值没出错,并且 id 值不同;

至于为什么 id 值会不同,只能在后面的进程控制才能讲解;

进程状态

 在之前我们使用 ps axj 命令查看进程的时候,可以看到有这样的一个字母:

 有一栏 STAT 的标题,下面有一个字母 S ;

这是表示什么呢?

实际上这是 linux 中用来表示进程状态的字符;

而进程的状态有许多种:

名称含义
R(运行状态)表明进程在运行或者在运行队列中
S(睡眠状态)表明进程在等待事件完成
D(磁盘休眠状态)不可中断的睡眠,需要等待IO结束或者强制断电
T(停止状态)发送SIGSTOP停止进程,SIGCONT来继续进程
X(死亡状态)这只是返回状态,无法看到这个状态
阻塞状态进程的pcb放在了某种资源(不包括CPU)的等待队列中
挂起状态当内存空间不够时,将阻塞的进程的代码和数据暂时放入磁盘中,被转移的进程就是挂起状态

在不同的操作系统下,这些状态可能会不同;

比如linux下的 s 状态其实就是阻塞状态的一种;

而T状态是比较有趣的一种;

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{

                        printf("I am child process!my pid = %d,ppid = %d\n",getpid(),getppid());


        return 0;

}

当我们编译并运行这个代码后,再 使用 kill -19 <pid> 的方式,它就会进入T状态

而在暂停之前,它的状态是 S+; 

并且此时可以用 ctrl + c 来强制停止这个进程;

 但是暂停后使用 kill -18 <pid> 的方式来继续,就会进程就会变为 S 状态

并且不能让使用ctrl + c 来停止这个进程;

只能使用 kill 命令杀死进程;

这说明 + 是有意义的;

状态后面带 + 号,表示前台进程,没 + 号表示后台进程,只可用kill命令杀死;

僵尸进程和孤儿进程

僵尸进程:子进程退出,但父进程未读取到子进程退出的返回代码时子进程的状态

孤儿进程:子进程未退出,但父进程提前退出时子进程的状态

首先我们讲讲僵尸进程

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
        pid_t id = fork();

        if(id == 0)
        {
                printf("I m child process! pid = %d \n",getpid());
                sleep(5);

                exit(1);
        }
        else
        {
                while(1){


                        printf("I m parent process! pid = %d \n",getpid());
                        sleep(1);
                }
        }
        return 0;
}

   

 

 代码中,子进程在休眠五秒后就退出,而父进程并未接收退出代码;

我们能够看到5秒后,子进程的状态变为了僵尸状态;

僵尸状态的危害

1.父进程一直不回收,那么子进程的PCB就一直要维护,就会占用资源

2.会造成内存泄漏

接下来将孤儿进程:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
        pid_t id = fork();

        if(id != 0)
        {
                printf("I m parent process! pid = %d \n",getpid());
                sleep(5);

                exit(1);
        }
        else
        {
                while(1){


                        printf("I m child process! pid = %d \n",getpid());
                        sleep(1);
                }
        }
        return 0;
}

 

 

 上面的代码我们的父进程在休眠五秒后,就会退出,而同时能够看到,子进程的状态由S+变成了S状态,并且子进程的 ppid 变成了 1 ,也就是所谓的 init进程;

总结:

1.父进程先退出,子进程会由系统回收;

2.回收原因是因为子进程成孤儿后,没有父进程接收退出信息,会导致子进程僵尸;

3.前台进程创建的子进程变成孤儿后,就会称为后台进程;

进程优先级

 由于计算机中的CPU或者硬件资源的缺席,进程之间通常需要争抢这些资源;

而有的进程比较重要有的没那么重要,因此操作系统在资源的分配上需要分出一个轻重缓急;

这个时候就出现了进程优先级;

而linux则是用两个数值共同决定一个进程的优先级

查看进程优先级

ps -la

#include<stdio.h>

int main()
{
        int a = 1+1;
        while(1)
        {
                a = 1+1;
        }
        return 0;
}

 我们随便写下一个死循环,然后使用ps -la的指令查看当前的所有进程;

我们能够看到一连串数字,而优先级有 PRI 和 NI 的数值决定

PRI进程的优先级,越小优先级越高
NI进程优先级的修正值(-20 ~ 19)

虽然PRI实际上的数值是上面的80,但实际上 优先级 = PRI + NI ;

而我们的 NI 值是能够修改的;

输入 top 命令,会出现如下界面:

 这里显示了各种进程们的pid以及优先级等一些值;

然后输入 'r' 表示修改 NI 值;

 然后输入想要修改的进程的 NI 值;

但是修改 NI 值有一定的风险,因此只有是有 sudo 提权或者 root 用户才能成功修改;

其他概念

1.竞争性:不同进程之前需要相互争夺CPU资源,因而有了优先级;

2.独立性:多进程同时运行,独享各种资源,并且相互不影响;

3.并行:多个进程在多个CPU下分别同时运行;

4:并发:多个进程在一个CPU下采用进程切换的方式,使得多进程在一段时间内得以推进

 

进程切换

一个CPU只能同时运行一个进程,但是我们平时使用计算器的时候,并不是只能使用一个软件,而是能同时进行多个软件,这就是CPU的进程切换;

我们都知道CPU中有一整套寄存器硬件,而每一个进程在CPU中都已一个时间片,当时间片计时结束后,就会切换进程;

但是我们的数据都在寄存器中,进程还需要继续用CPU进行运算,那么我们该怎么办呢?

这个时候操作系统就会先保存寄存器内的上下文数据,然后再切换进程,当进程切换回来后,再根据上下文数据来继续上次的运算;

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

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

相关文章

19/365 java 多线程

1. 基础概念 程序&#xff1a;指令集和数据的集合。&#xff08;静态&#xff09; 进程&#xff1a;对程序的一次执行。&#xff08;动态&#xff09; 对同一个程序&#xff0c;执行两次&#xff0c;那就是两个进程。 进程是系统资源分配的基本单位 线程&#xff1a;一个进程…

gma 1.1.2 (2023.01.14) 更新日志(重大更新:开始支持空间绘图)

重大更新&#xff1a;从本版本开始&#xff0c; gma 逐步 支持空间绘图功能&#xff08;依赖 matplotlib&#xff09;&#xff01; 获取 gma 1.1.2 1、百度网盘&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1eT2rJRiUDJuJkWeLJNL-cw?pwdb07n 提取码&#xff1a;b…

基于SIMULINK的动力电池CAN通信仿真教程

在真实的整车开发过程中&#xff0c;整车厂一般会先设计出整车网络架构&#xff0c;并依据此架构及ECU之间的功能交互设计网络总线数据库&#xff08;Database&#xff09;, 作为重要的技术文档&#xff0c;可以根据需 要全部或部分地公开给各个ECU供应商。也存在一些特殊情况&…

【渗透测试】web端姿势-前端利用

目录 前端 存在问题 关于密码重置 jwt攻击 jwt介绍 工具使用 学习来源 前端 存在问题 任意用户注册 未授权访问&#xff0c;直接访问对应链接&#xff0c;可得到系统权限 可爆破用户名 爆破用户名&#xff0c;密码 用户名注入 万能密码 用户名Xss 修改返回包信息&#…

(三)计算机组成原理——总线

文章目录&#xff08;三&#xff09;计算机组成原理——总线总线的基本概念单总线双总线面向CPU以存储器为中心总线的分类片内总线系统总线数据总线地址总线控制总线通信总线总线特性及性能指标总线特性机械特性电气特性功能特性时间特性性能指标总线标准总线结构单总线多总线双…

3.1 python高阶应用

文章目录闭包装饰器设计模式单例模式工厂模式多线程进程、线程和并行执行多线程编程网络编程服务端开发客户端开发正则表达式基础匹配元字符匹配递归闭包 def account_create(inital_account 0) :def atm(num:int,deposite:bool True) :# 声明inital_account是外部声明的init…

【Ajax】服务器的基本概念

一、客户端与服务器上网的目的通过互联网的形式来获取和消费资源。2. 服务器上网过程中&#xff0c;负责存放和对外提供资源的电脑&#xff0c;叫做服务器。3. 客户端上网过程中&#xff0c;负责获取和消费资源的电脑&#xff0c;叫做客户端。二、URL地址URL地址的概念URL&…

工业互联网2022:第一梯队成型、专精玩家突围

文|智能相对论作者|沈浪回顾2022年&#xff0c;市场依旧对工业互联网领域保持着高度的热情与专注。近期&#xff0c;IDC、Gartner等各大国际研究机构接连发布多份工业互联网相关报告&#xff0c;包括《2022年度中国工业互联网平台企业侧市场分析报告》《2022年度工业互联网平台…

唯一杰出级!百度智能云曦灵获信通院权威认证

​中国信通院公布“数字人系统评测结果” 百度智能云曦灵平台 继首批通过48项基础能力评测后 在第二轮性能分级评测中 以超高分获得行业唯一“杰出级”证书 代表了当前数字人的最高标准 该评测标准依托国际电信联盟&#xff08;ITU&#xff09;、中国通信标准化协会&#xff08…

JNPF低代码开发平台 全新版本 使用讨论 多用户商城系统源码 框架源码部署文档

JNPF快速开发平台是一套成熟的快速开发框架&#xff0c; JNPF作为承重墙&#xff0c;强大支撑保障&#xff0c;提供所有操作系统的生长土壤&#xff0c;JNPF快速开发平台采用前后端分离技术、采用B/S架构开发&#xff0c;形成一站式开发多端&#xff08;APPPC&#xff09;使用&…

【手写 Vue2.x 源码】第二十九篇 - diff算法-节点比对

一&#xff0c;前言 上篇&#xff0c;diff 算法问题分析与 patch 方法改造&#xff0c;主要涉及以下几点&#xff1a; 初始化与更新流程分析&#xff1b;问题分析与优化思路&#xff1b;新老虚拟节点比对模拟&#xff1b;patch 方法改造&#xff1b; 下篇&#xff0c;diff 算…

Mysql的锁问题:

Mysql的锁问题&#xff1a; 1.1锁的概述&#xff1a; ​ Mysql锁的机制比较简单&#xff0c;不同的存储引擎支持不同的锁机制&#xff1a;MyISAM和MEMORY存储引擎支持表级锁&#xff1b;DBD支持页面锁&#xff0c;但是它也支持表级锁&#xff1b;InnoDB既支持行级锁也支持表级…

23-1-18 文件上传

步骤 file01 / file02 分别是两台java服务 功能: 主要负责接收用户上传的文件存储在指定目录 并记录(上传时间、上传人、文件信息(大小&#xff0c;源文件名&#xff0c;存储后的文件名 ....) 文件权限(共享、私有))。负责接收处理用户的下载请求&#xff0c;用户可以根据文件…

【开发Log】C++QT连连看

1.10开发的初衷是闲来无事开了把宠物连连看&#xff0c;然后发现打了几遍第一关都过不去&#xff0c;于是想自己写个&#xff0c;这样就可以任意使用提示次数了&#xff08;bushi。其实今天正好是老妈生日&#xff0c;问了下老妈她竟然还玩连连看&#xff0c;还ak了orz。于是乎…

分布式理论

目录 1.定义 2.关键技术 3.关键问题 4.基本定理 4.1.CAP定理 4.2.BASE定理 1.定义 分布式的本质是一系列计算机集群通过网络共同完成一串连贯的任务。 2.关键技术 分布式主要关注的几个关键点技术是&#xff1a; 性能容错通信 性能&#xff1a; 可扩展性&#xff0c…

深度学习入门基础CNN系列——池化(Pooling)和Sigmoid、ReLU激活函数

想要入门深度学习的小伙伴们&#xff0c;可以了解下本博主的其它基础内容&#xff1a; &#x1f3e0;我的个人主页 &#x1f680;深度学习入门基础CNN系列——卷积计算 &#x1f31f;深度学习入门基础CNN系列——填充&#xff08;padding&#xff09;与步幅&#xff08;stride&…

Acwing - 算法基础课 - 笔记(数学知识 · 三)(补)

数学知识&#xff08;三&#xff09; 这一小节讲的是高斯消元&#xff0c;组合数。 高斯消元 高斯消元是用来解方程的&#xff0c;通常来说可以在 O(n3)O(n^3)O(n3) 的时间复杂度内&#xff0c;求出包含 n 个未知数的&#xff0c;n个方程的多元线性方程组的解。如下的方程组…

人机界面石油行业应用:一个设备构建石油罐区状态监测系统

一、应用背景 石油罐区是石油石化企业重要的生产设施&#xff0c;负责存储和输送各类油品&#xff0c;而石油罐区状态参数的监控是生产管理的重要部分&#xff0c;不仅可以及时准确地获取现场设备数据&#xff0c;保证罐区的正常运行&#xff0c;还可以防止安全事故的发生。 …

Python如何解决“快手滑块验证码”(4)

前言 本文是该专栏的第32篇,后面会持续分享python的干货知识,记得关注。 很多时候,我们打开一个页面还没开始进行浏览,就跳出一个滑块验证的图片,需要拖到滑块至缺口处,才可以正常浏览。这对于我们正常人浏览页面来说,几乎没什么难度,但是当我们需要用到脚本去实现的时…

本地服务器如何让外网远程桌面连接?

远程访问是远程办公和服务器管理常用的网络应用场景。那么&#xff0c;当我们需要面对远程目标主机是内网服务器电脑时&#xff0c;在不是同个局域网的跨网环境下&#xff0c;内网可以远程控制电脑吗&#xff1f;答案是可以&#xff0c;使用快解析内网映射方案就能实现将本地服…