Linux进程初识:OS基础、fork函数创建进程、进程排队和进程状态讲解

news2025/1/11 21:04:35

目录

1、冯诺伊曼体系结构

问题一:为什么在体系结构中存在存储器(内存)?

存储单元总结:

问题二:为什么程序在运行的时候,必须把程序先加载到内存?

问题三:请解释,从你登录上qq开始和某位朋友聊天开始,数据的流动过程。

2、操作系统

2.1操作系统的概念:

我们首先要明白什么是管理:

2.2为什么要有操作系统?

2.3操作系统如何保证稳定和安全呢?(利用系统调用函数解决)

库函数和系统调用的关系:

3、那到底什么是进程呢?(重要!)

3.1、什么程序加载到内存,变成一个进程之后,我们要给每一个进程形成一个PCB对象呢?

3.2、PCB进程标识符:

4、fork函数初识

4.1、fork函数的作用:

4.2、使用方法(一般都用if分流)

4.3、关于fork函数的灵魂三问:

1、为什么给父进程返回子进程的pid,给子进程返回0?

2、fork函数为什么会返回两次?

3、这里的id为什么会同时满足 == 0 又满足>0呢?

问题:为什么我们在磁盘上将一个程序删了,这个程序还能运行呢?

5、进程排队:

6、进程状态:

6、1那什么是挂起状态呢?

6.2、Linux下具体的进程状态:

D状态深度睡眠又是什么呢?

6.3、为什么要有Z状态?

6.4、什么是僵尸Z状态?

6.5、僵尸进程危害:

7、什么是孤儿进程?

1、冯诺伊曼体系结构

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

  • 输入单元:包括键盘, 鼠标,扫描仪, 写板等
  • 中央处理器(CPU):含有运算器和控制器
  • 输出单元:显示器,打印机等
  • 存储器:指的是内存(掉电易失)
  • 运算器主要进行算术运算(加减乘除)和逻辑运算(判断真假)

设备是互相连接的,目的是让设备之间数据流动,本质是让设备之间进行数据的来回拷贝(拷贝的整体速度,是决定计算机效率的重要指标

问题一:为什么在体系结构中存在存储器(内存)?

输入输出设备的运行速度就会拖累cpu的运行速度,跟木桶原理一个道理,那存储器并没有解决短板的问题,那怎么提高运行速度呢?

我们把内存看做一个非常大的缓存,介于设备和CPU之间
利用预存和缓存的机制,将计算机的效率最终变成了内存效率为主

存储单元总结:

距离CPU越近的存储单元,效率越高,造价贵,单体容量越小

距离CPU越远的存储单元,效率越低,造价便宜,单体容量大

所以内存的引入,可以让我们的计算机效率不错,且价格比较便宜,这样我们才能买的起电脑

问题二:为什么程序在运行的时候,必须把程序先加载到内存?

因为冯诺依曼体系决定的!

在数据层面,CPU只和内存打交道;外设只和内存打交道

关于冯诺依曼,必须强调几点:
这里的存储器指的是内存
不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备)
外设(输入或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取。
一句话,所有设备都只能直接和内存打交道

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

问题三:请解释,从你登录上qq开始和某位朋友聊天开始,数据的流动过程。

我们先通过键盘输入消息,然后加载到内存,CPU从内存中读取数据,进行加密和计算后再放到内存,显示器(显示消息到屏幕上)和网卡(发送数据到网络)再从内存中读取数据。(忽略网络部分处理细节)

        朋友电脑的网卡从网络上获取到了我们发送的数据,然后加载到内存,CPU从内存中读取数据,进行解密和计算后再放到内存,显示器再从内存读取相关的数据,显示到屏幕上。

总的来说,就是外设->内存->CPU->内存->外设

2、操作系统

2.1操作系统的概念:

操作系统是一个进行软硬件资源管理软件

我们首先要明白什么是管理

管理就是做决策+做执行。

管理者和被管理者,并不需要见面,管理的本质是对人的信息(数据)做管理。

管理者的核心工作是做决策,根据数据做决策。

总结为六字真言:

先描述,再组织

语言的本质就是对数据的管理

2.2为什么要有操作系统?

对下管理好软硬件资源(手段),对上提供一个良好(稳定、高效、安全)的运行环境(目的)

2.3操作系统如何保证稳定和安全呢?(利用系统调用函数解决)

任何人不得访问操作系统中的任何数据,需要利用系统调用的函数

不能直接越过操作系统!系统调用接口很重要

所谓的系统调用接口,其实就是函数,用C语言设计的函数,由操作系统提供:系统调用函数

库函数和系统调用的关系:

只要库函数调用了系统调用,他们两个就必然是上下层的关系,库函数在上,系统调用在下

3、那到底什么是进程呢?(重要!)

进程 = 内核PCB对象(内核的数据结构) + 可执行程序

这里的PCB到底是何方神圣呢?进程控制块(process control block)

在Linux环境下,PCB就是task_struct,存储进程的所有属性,操作系统内部的数据

未来,所有对进程的控制和操作,都只和进程的PCB有关,和进程的可执行程序没有关系

我们所说的让一个进程去排队,本质上是让PCB去排队,而不是让可执行程序去排队

对进程的管理,转换为对PCB对象的管理

3.1、什么程序加载到内存,变成一个进程之后,我们要给每一个进程形成一个PCB对象呢?

因为操作系统要进行管理!(先描述,再组织)

PCB这些内容都是在操作系统内部的数据

task_ struct内容分类

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

3.2、PCB进程标识符:

下面主要讲解标识符,描述进程的唯一标识符,用来区别其他进程

getpid是我们第一个学习的系统调用函数,用来获得该进程的标识符。

每一次启动进程的pid几乎都会变化,因为我的进程是一个新的进程!

一般在Linux中,普通进程,都有他的父进程!

通过系统调用获取进程标示符
进程id(PID)
父进程id(PPID)

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
printf("pid: %d\n", getpid());
printf("ppid: %d\n", getppid());
return 0;
}

4、fork函数初识

4.1、fork函数的作用:

通过系统调用创建进程。它的作用是从已经存在的进程中创建一个子进程,而原进程称为父进程

4.2、使用方法(一般都用if分流)

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int ret = fork();
if(ret < 0){
perror("fork");
return 1;
}
else if(ret == 0){ //child
printf("I am child : %d!, ret: %d\n", getpid(), ret);
}else{ //father
printf("I am father : %d!, ret: %d\n", getpid(), ret);
}
sleep(1);
return 0;
}

4.3、关于fork函数的灵魂三问:

1、为什么给父进程返回子进程的pid,给子进程返回0?

  • 在‌父进程中‌,fork函数返回新创建子进程的进程ID。这是因为父进程需要通过这个返回值来跟踪和管理其创建的子进程。
  • 在‌子进程中‌,fork函数返回0。这是因为子进程可以通过这个返回值来判断它是否成功创建,并且由于子进程只有一个父进程,它的ID可以通过getppid()获得父进程的ID,而子进程的ID(虽然与父进程ID不同)在fork函数返回时已经被系统内部记录下来。

父进程会有多个子进程,但是子进程只会有一个父进程,一对多的关系

2、fork函数为什么会返回两次?

当fork函数被调用时,它会创建一个新的子进程,这个子进程是父进程的一个复制品,它们共享相同的代码段和部分数据段。由于子进程是父进程的一个副本,因此它们都会执行fork函数之后的代码。这就导致了fork函数在父进程和子进程中都会“返回”,但返回的值不同

fork之后,我们的父和子都会进行,代码共享,一般而言,我们想让父子做不同的事情。调用fork函数,会返回不同的值分别给父子进程

父子进程执行不同的代码块

3、这里的id为什么会同时满足 == 0 又满足>0呢?

这是因为有两个进程,进程之间是具有独立性,互相不能影响!

问题:为什么我们在磁盘上将一个程序删了,这个程序还能运行呢?

我们在运行一个程序时,本质是把程序从磁盘拷贝到内存,换句话来说就是你把这个程序在磁盘上删了,但是这个程序比较小,已经拷贝到内存,在内存上运行了,成为一个进程,就与磁盘上的程序没有关系了

5、进程排队:

进程为什么会排队呢?一定是在等待某种“资源”,比如下面的scanf就需要等待键盘给他传输资源。

只要是排队,一定是进程的task_struct进行排队。

6、进程状态:

教材上关于进程状态的表述:运行、阻塞、挂起

所谓的状态,本质就是一个整形变量,在task_struct中的一个整型变量

状态决定了什么?决定了你的后续动作,Linux中可能会存在多个进程都要根据它的状态执行后续动作(进程开始排队了!)

当我们的进程在进行等待软硬件资源的时候,资源如果没有就绪,我们的进程task_struct只能1、将自己设置为阻塞状态2、将自己的PCB连入等待的资源提供的等待队列。

状态的变迁,引起的是PCB会被OS变迁到不同的队列当中。

当我们的软硬件资源准备就绪后,进程状态就会从阻塞状态调整到运行状态!

6、1那什么是挂起状态呢?

我们这里主要讲的是阻塞挂起,这个状态的前提是计算机资源比较吃紧了

挂起状态就是将数据从内存,换出到磁盘上面 ,当计算机资源恢复后,数据会从外设转入到内存中

6.2、Linux下具体的进程状态:

为了弄明白正在运行的进程是什么意思,我们需要知道进程的不同状态。一个进程可以有几个状态下面代码是状态在kernel源代码里定义:

static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
  • R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
  • S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。
  • D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
  • T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的程序可以通过发送 SIGCONT 信号让进程继续运行。
  • X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

S状态其实与操作系统中的阻塞状态(等待某种资源)是一致的!!!

D状态深度睡眠又是什么呢?和S睡眠有什么区别?

深度睡眠,不可中断睡眠。

相当于给进程一个免死金牌,我们要知道在Linux环境下,在操作系统逼急的时候,是会杀掉进程!如果这个进程很重要,就会造成很大的损失,因此这个D状态就相当于给了进程一个免死金牌,不会被进程所杀掉。

注意D状态依旧是阻塞状态

kill -19 pid 就会让一个进程进入T状态,也就是暂停状态

继续运行就是 kill -18 pid

子进程最终的状态都是Z

注意状态标识后面有+,就代表是前台进程,可以直接^C杀死,但是如果没有+,就说明这个进程变成了后台进程,不能用^C杀死,只能kill-9方法

后台进程,我们用普通的^C是停止不掉的,那怎么停止呢?

我们可以使用这样的命令:kill -9 pid(该进程的pid)

6.3、为什么要有Z状态?

创建进程是希望这个进程给用户完成工作的,子进程必须得有结果数据返回给父进程

6.4、什么是僵尸Z状态?

僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用,后面讲)
没有读取到子进程退出的返回代码时就会产生僵死(尸)进程
僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态

6.5、僵尸进程危害:

进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎
么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!
维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话
说,Z状态一直不退出,PCB一直都要维护?是的!
那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?也就会造成内存的泄露!

7、什么是孤儿进程?

父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?
父进程先退出,子进程就称之为“孤儿进程”

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

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

相关文章

爆改YOLOv8|利用yolov10的SCDown改进yolov8-下采样

1, 本文介绍 YOLOv10 的 SCDown 方法来优化 YOLOv8 的下采样过程。SCDown 通过点卷积调整通道维度&#xff0c;再通过深度卷积进行空间下采样&#xff0c;从而减少了计算成本和参数数量。这种方法不仅降低了延迟&#xff0c;还在保持下采样过程信息的同时提供了竞争性的性能。…

使用Python通过字节串或字节数组加载和保存PDF文档

处理PDF文件的可以直接读取和写入文件系统中的PDF文件&#xff0c;然而&#xff0c;通过字节串&#xff08;byte string&#xff09;或字节数组&#xff08;byte array&#xff09;来加载和保存PDF文档在某些情况下更高效。这种方法不仅可以提高数据处理的灵活性&#xff0c;允…

Mysql8客户端连接异常:Public Key Retrieval is not allowed

mysql 8.0 默认使用 caching_sha2_password 身份验证机制 &#xff08;即从原来mysql_native_password 更改为 caching_sha2_password。&#xff09; 从 5.7 升级 8.0 版本的不会改变现有用户的身份验证方法&#xff0c;但新用户会默认使用新的 caching_sha2_password 。 客户…

ISO26262和Aspice之间的关联

ASPICE 介绍&#xff1a; ASPICE&#xff08;Automotive Software Process Improvement and Capability dEtermination&#xff09;是汽车软件过程改进及能力评定的模型&#xff0c;它侧重于汽车软件的开发过程。ASPICE 定义了一系列的过程和活动&#xff0c;包括需求管理、软…

基于yolov8的抽烟检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的抽烟检测系统是一种利用先进深度学习技术实现的实时目标检测系统。该系统采用YOLOv8算法&#xff0c;该算法以其高速度和高精度在目标检测领域脱颖而出。该系统通过训练大量标注好的抽烟行为数据集&#xff0c;使模型能够自动识别和定位视频或图像中…

使用YOLOv10训练自定义数据集之二(数据集准备)

0x00 前言 经过上一篇环境部署的介绍【传送门】&#xff0c;我们已经得到了一个基本可用的YOLOv10的运行环境&#xff0c;还需要我们再准备一些数据&#xff0c;用于模型训练。 0x01 准备数据集 1. 图像标注工具 数据集是训练模型基础素材。 对于小白来说&#xff0c;一般…

如何判断小程序是运行在“企业微信”中的还是运行在“微信”中的?

如何判断小程序是运行在“企业微信”中的还是运行在“微信”中的&#xff1f; 目录 如何判断小程序是运行在“企业微信”中的还是运行在“微信”中的&#xff1f; 一、官方开发文档 1.1、“微信小程序”开发文档的说明 1.2、“企业微信小程序”开发文档的说明 1.3、在企业…

redis缓存预热、缓存穿透的详细教程

前言 作此篇主要在于关于redis的缓存预热、缓存雪崩、缓存击穿和缓存穿透在面试中经常遇到&#xff0c;工作中也是经常遇到。中级程序员基本上不可避免要克服的几个问题&#xff0c;希望一次性解释清楚 缓存预热 MySQL加入新增100条记录&#xff0c;一般默认以MySQL为准为底单…

5-2 检测内存容量

1 使用的是bios 中断&#xff0c; 每次进行检测都会返回一块 内容。并且标志上&#xff0c;这块内存是否可用。 接下来是代码&#xff1a; 首先是构建 一个文件夹&#xff0c; 两个文件。 types.h 的内容。 #ifndef TYPES_H #define TYPES_H// 基本整数类型&#xff0c;下面的…

C++系统教程002-数据类型(01)

一、数据类型 学习一门编程语言&#xff0c;首先要掌握它的数据类型。不同的数据类型占用的内存空间不同&#xff0c;定义数据类型合理在一定程度上可以优化程序的运行。本次主要介绍C中常见的数据类型及数据的输入与输出格式。本章知识架构及重难点如下&#xff1a; &#xf…

linux监听网速

方法一 tcpdump -i ens33 -w - | pv -bert > /dev/null方法二

问题 J: 数据结构基础33-查找二叉树

题目描述 已知一棵二叉树用邻接表结构存储&#xff0c;中序查找二叉树中值为x的结点&#xff0c;并指出是第几个结点。例&#xff1a;如图二叉树的数据文件的数据格式如下 输入 第一行n为二叉树的结点个树&#xff0c;n<100&#xff1b;第二行x表示要查找的结点的值&…

windows环境安装OceanBase数据库并创建表、插入数据

windows环境安装OceanBase数据库并创建表、插入数据 前言&#xff1a;OceanBase数据库目前不支持直接在Windows环境下安装&#xff0c;安装比较麻烦&#xff0c;记录一下安装过程 1.安装方案 根据官方文档&#xff1a;https://www.oceanbase.com/docs/common-oceanbase-databa…

实验六 异常处理

实验目的及要求 目的&#xff1a;了解异常的概念&#xff0c;掌握异常处理的方法&#xff0c;掌握throws与throw关键字的区别与联系&#xff0c;掌握自定义异常的方法及用途。 要求&#xff1a; &#xff08;1&#xff09;编写程序了解程序中可能出现的运行时异常与非运行时…

摆花 NOIP2012普及组

目录 思路 代码 思路 代码 #include <iostream> #include <algorithm>using namespace std; using LL long long;const int N 1e2 9; const int mod 1e6 7;int n,m; LL a[N]; LL f[N][N];void solve() {cin >> n >> m;f[0][0] 1;for (int i 1;…

Jmeter模拟用户登录时获取token如何跨线程使用?

一、用户定义的变量 1、添加"用户定义的变量" 2、填写"host、port" 二、setUp线程组 1、添加"setUp线程组" 2、设置循环次数"100" 三、CSV 数据文件设置 1、添加"CSV 数据文件设置" 2、填写信息"用户登录数据.csv、…

2024 天池云原生编程挑战赛决赛名单公布,9 月 20 日开启终极答辩

历时 4 个月&#xff0c;2024 天池云原生编程挑战赛决赛名单公布&#xff01; 本届大赛规模创新高&#xff0c;参赛战队达 20000 支&#xff0c; 广覆盖国内外优秀高校和杰出企业&#xff01;吸引了来自北京大学、清华大学等 176 所国内外优秀高校&#xff0c;以及美团、米哈游…

vue3+ts项目import导入路径用@/报错找不到模块“@/components/也没有快捷提示

解决办法 在tsconfig.json文件中加入以下代码 "compilerOptions": {"baseUrl": ".","paths": {"/*": ["./src/*"] }}, 喏 ☟

【开端】服务器间免密登录配置

1.首先进入源 服务器中&#xff0c;进入/root/.ssh路径下 2.将路径下的”id_rsa.pub”文件复制到目标服务器的/root/.ssh路径下 3.打开目标服务器/root/.ssh路径中的“authorized_keys”文件&#xff0c;如没有则创建&#xff0c;并将”id_rsa.pub”文件中的内容复制到“auth…

ctfshow-爆破(web21-web28)

web21 提交用户和密码后发现没有用户以及密码的值呢 常见的是在post数据中 或者url后传值 但这里都没有 发现http头有一个Authorization字段 值是base64编码后的 解码 原来是将传入的值用冒号分离进行base64编码然后放到了Authorization字段中了 设置变量 增加前缀 增加编码方…