Linux——进程基本概念中篇

news2025/1/18 11:45:09

Linux——进程基本概念中篇


文章目录

  • Linux——进程基本概念中篇
  • 一、通过系统调用创建进程——fork
    • 1.1 fork的理解
    • 1.2 fork的返回值
  • 二、进程状态
    • 2.1 运行状态
    • 2.2 睡眠状态和休眠状态
    • 2.3 停止状态和死亡状态
    • 2.4 僵尸进程
    • 2.5 孤儿进程
    • 2.6 前台和后台进程
  • 三、进程优先级
    • 3.1 查看优先级
    • 3.2 调整优先级
    • 3.3 并行与并发
  • 四、 Linux进程调度之大O(1)调度算法
    • 4.1活动队列
    • 4.2 过期队列
    • 4.3 active指针和expired指针


一、通过系统调用创建进程——fork

通过上篇文章我们了解到,进程 = 可执行程序 + 内核数据结构(PCB) 而操作系统OS就是通过PCB中的内容来管理进程,同时我们也了解到每个PCB中含有着自己的标识符——pid,我们需要额外了解的是对于每一个新创建的进程,其实都是由他的父进程创建而来,所以除了pid以外还有一个ppid来标志这个进程的父进程

在这里插入图片描述

1.1 fork的理解

创建进程有三种方式:

  1. 运行程序
  2. 执行命令
  3. 调用fork

由于创建进程的本质就是进程 = 可执行程序(代码和数据) + 内核数据结构(PCB) ,三者在创建本质上是没有区别的

运行程序是./文件名执行我们通过gcc或者g++编译好的可执行文件,而执行命令其实是Linux将一些常用功能写好打包通过环境变量使得系统能自动找到文件地址,直接输入文件名就能够直接执行

fork的本质是通过函数调用创建一个进程,而这个进程就需要可执行程序(代码和数据) + 内核数据结构(PCB),但fork是一个函数,是写在一段代码中的,只有当这段代码被编译执行成为一个进程(这里我们称为源进程),才会真正调用fork,但这个通过fork创建的新进程的代码从哪里来呢?

当源进程通过fork函数调用创建了一个新进程的时候,操作系统肯定也需要给新进程创建PCB,而代码和数据则是拷贝源进程的,所以我们一般称源进程为父进程,新进程为子进程

默认情况下会继承父进程的代码和数据,而且PCB也会以父进程为模板,初始化子进程的PCB(上下文信息也会继承,所以子进程fork前的代码不会运行),要注意代码是不可修改的(只读)

默认情况下会继承父进程的代码和数据,但也有特殊情况:对于父子都有的变量一个变量,父子任意一方将其修改,使得父进程与子进程中这个变量的值不同的时候,这时操作系统会针对变量发生写实拷贝,父子分别是两个值,因为进程具有独立性

这里补充写实拷贝的概念
由于进程具有独立性,当一个进程的数据发生修改,为了不让另一个进程也被改变,所以会拷贝一份数据再修改
好处:提高效率(不修改就共享)

1.2 fork的返回值

当调用fork函数时,系统就帮我们创建了一个新的进程,而我们创建一个子进程的目的肯定是需要执行与父进程不同的任务,这时就势必需要通过选择结构来区分父子进程

通过fork的返回值

失败:返回 -1
成功
1️⃣ 给父进程返回子进程的pid
2️⃣ 给子进程返回0

在这里插入图片描述

在这里插入图片描述
如何理解一个函数会有两个返回值?

其实当fork执行到return语句的时候,fork的主要工作已经做完了,也就是说这时已经创建出了子进程,而我们上文中说到,子进程会和父进程有一样的代码和数据,其中就包括上篇中讲到的PC指针,它用于指向下一条需要执行的代码,所以这里看似是两个返回值,实际是父子进程各返回了一次,并且返回的值不同,而用于接收的变量n,由于父子之间的值不同,发生了写实拷贝

值得注意的是,fork后父子进程之间谁先被执行是不确定的,需要看CPU如何调度,先调度谁,谁先执行

二、进程状态

首先想想为什么要有进程状态?

进程状态可以方便OS快速判断进程的状态,方便使其完成各种功能,本质是一种分类

linux中的进程一般有以下状态

R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里
S睡眠状态(sleeping):意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep)
D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束
T停止状态(stopped):可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT信号让进程继续运行
X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

2.1 运行状态

在上篇中提到需要被运行的进程的PCB都被链接到一个运行队列中,在一个时间片中提供给CPU执行,到了下一个时间片就切换下一个进程,所以队列中的进程在排队被CPU调度

只要在运行队列中,所有的状态都叫做R状态,随时被CPU调用

2.2 睡眠状态和休眠状态

这两个状态实际上都是因为执行程序所需要的资源没有准备好,比如键盘的输入等等,这时由于资源不就绪,程序无法继续执行,进程就会被睡眠,等待资源就绪了才会被唤醒

这些处于睡眠或者休眠状态的进程会根据等待资源的不同,被链入不同的等待队列,比如等待键盘输入的会被链入键盘等待队列,等待磁盘读数的被链入磁盘等待队列

总结

等CPU资源的队列叫运行队列
等外设资源的队列叫等待队列
当PCB1一旦获取磁盘资源,就会把PCB1的状态改成R(被唤醒),放入运行队列中,等到他获取CPU资源的时候,再读取磁盘
从运行队列到等待队列叫做挂起等待也叫阻塞,从等待队列到运行队列叫唤醒进程

一个进程可能因为运行的需要,在不同的队列里,每个队列代表不同的运行状态

睡眠状态(S)和休眠状态(D)的区别?

S是浅度睡眠,是可以中断的
D是深度睡眠,不可中断

为什么要有两种“睡眠”状态?

当一个进程想要往磁盘写入数据,写入磁盘需要时间,此时该进程就在内存等待结果(处于休眠状态),如果此时可用资源比较少,该进程就会被OS杀死,那么磁盘写入结果的返回就无法送达,可能会引发问题,但是如果是D状态,OS也无法杀死

为什么数据刷新这么快,还是S状态?

在这里插入图片描述

在这里插入图片描述

数据写入显示器需要时间,而CPU写入的速度太快了(比IO快得多),所以我们以为进程一直在执行,其实进程大部分时间在休眠

2.3 停止状态和死亡状态

停止状态T跟睡眠状态S很像,都可以挂起进程,那么他们有什么区别呢?

睡眠状态S虽然什么事都没干,但会更新核心数据,比方说我们写了个sleep(10);到了10秒就会唤醒该进程
而停止状态T就是彻底暂停,不会更新数据,直到人为改变

停止状态就像我们平时调试的时候打的断点,程序运行起来的时候会自动运行到断点的时候停下来,这时就是停止状态

实现原理:信号

kill -19 可以暂停进程
kill -18 可以继续进程

死亡状态(X)
我们在创建进程的时候需要代码数据和PCB,当进程死亡的时候,也要把这些资源回收回去

kill -9 可以杀死进程

2.4 僵尸进程

当一个进程在退出的时候,退出信息会由OS写入到当前退出进程的PCB中,可以允许进程的代码和数据空间被释放,但是不能允许进程的PCB被立即释放,因为进程在退出的时候,要有些退出信息,表明自己把任务完成的怎么样

但当进程退出的时候,进程的所有资源不会立即回收,而是进入僵尸状态(Z),把数据暂时保存(要写入退出信息),目的是为了判断是否将任务成功完成

资源是由父进程进行回收
如果一个进程Z状态了,但是父进程就是不回收它,PCB就要一直存在?

是的,如果父进程一直不回收,PCB就会一直存在

所以僵尸进程我们需要尽量避免,因为会导致过度占用空间和内存泄漏

验证:我们可以让父进程休息,然后杀死子进程就可以看到僵尸状态

在这里插入图片描述

在这里插入图片描述

2.5 孤儿进程

字面意思,父子进程同时运行,父进程被杀掉,子进程就变成了孤儿进程
孤儿进程将会被1号进程(OS本身)领养

在这里插入图片描述

在这里插入图片描述
如果是前台进程创建的子进程,如果孤儿了,会变成后台进程

2.6 前台和后台进程

有的状态有的后面带+号有的不带,这表示什么呢?

后面带+号表示前台进程
后面不带+号表示后台进程

区别:

前台进程运行时我们无法输入任何指令,但可以Ctrl + c干掉进程
而后台进程运行的时候可以执行命令,但是Ctrl+ c不能干掉进程,想要杀死就用kill -9

三、进程优先级

首先要知道为什么有优先级,本质是因为资源不足
优先级也是PCB中的一个数据
它决定了程序获得CPU资源的顺序

Linux进程的优先级数值范围: 60 ~99
Linux中默认进程的优先级都是:80

3.1 查看优先级

ps指令

作用:ps指令主要用来显示linux进程信息
选项:-a 显示所有进程

PRI与NI

PRI :代表这个进程可被执行的优先级,其值越小越早被执行,默认值为80
NI :优先级修正数据,取值范围(-20 ~ 19)

Linux进程pcb中存在一个nice值:进程优先级的修正数据
pri(新)= pri(old) + nice

注意

old pri都是从80开始的
nice调整最小是:-20,超过部分统一当成-20
nice调整最大是:19,超过部分统一当成19

在这里插入图片描述
总结
PRI的最终值也取决于NI值(PRI=80+NI)NI范围:[-20,19]

3.2 调整优先级

调整优先级其实就是调整NI值

输入top后按r->输入进程pid->输入nice

我们知道NI的范围只能是-20 ~ 19,那么为什么不让范围更大呢?

OS调度的时候,要较为均衡的让每一个进程都要得到调度
优先级不管怎么调也只是相对的优先,不能出现绝对的优先,不然会让一些进程一直得不到资源,形成进程饥饿

3.3 并行与并发

并行

多个进程在多个CPU下分别,同时进行运行,就是在任意时刻都有两个以上的进程在运行,这称之为并行

并发:

多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发(也就是之前说的等待队列中的时间片调度)

四、 Linux进程调度之大O(1)调度算法

前面我们了解到进程之间有优先级,但优先级也分实时优先级和普通优先级,在上文中提到的优先级就是普通优先级,这里我们暂不考虑实时优先级

在这里插入图片描述

4.1活动队列

那么在Linux系统中,OS到底是如何根据进程的优先级来调度进程的呢?

OS会在系统内维护一个运行队列,我们着重看上图队列中蓝色和红色的部分,队列中会维护两个队列,分别是活跃队列和过期队列,操作系统会根据活跃队列中优先级的顺序依次调用活跃队列中的进程,直到队列中的进程全部被执行
过程
1. 从0下表开始遍历queue[140]
2. 找到第一个非空队列,该队列必定为优先级最高的队列
3. 拿到选中队列的第一个进程,开始运行,调度完成
4. 遍历queue[140]时间复杂度是常数,但还是太低效了

那么如何优化这个过程呢?

运行队列中维护了一个bitmap[5] 32 bit * 5 = 160bit 可以记录160个位置的存在信息,一共有140个优先级,所以有140个进程队列,为了提高查找非空队列的效率,就可以用5*32个比特位表示队列是否为空,这样便可以大大提高查找效率,此时效率近似于O(1)

4.2 过期队列

如果在操作系统调用活跃队列的途中,来了许多新进程呢,并且新进程比现在执行的进程优先级还高怎么办呢?

新来的进程会按照优先级依次链入过期队列中,等待活跃队列执行完,当活跃队列中没有进程需要执行的时候,OS就会将指向活跃队列的指针和指向过期队列的指针进行交换,这样活跃队列中又有进程了,并且还能保证一定的调度公平性

过期队列和活动队列结构一模一样
过期队列上放置的进程,都是时间片耗尽的进程
当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算

4.3 active指针和expired指针

active指针永远指向活动队列
expired指针永远指向过期队列

可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在

在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了一批新的活动进程

在这里插入图片描述


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

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

相关文章

redis中的集群模式

主从复制、主从同步(解决高并发读的问题) 主从同步原理: 1.全量同步 slave(从节点)每次请求数据同步会带两个参数:replid和offset。 replid:第一次请求同步时,replid和master的replid不一样,这…

使用FPGA实现逐级进位加法器

介绍 逐级进位加法器就是将上一位的输出作为下一位的进位输入,依次这样相加。下面以一个8位逐级进位加法器给大家展示。 我增加了电路结构,应该很容易理解吧。 下面我也列举了一位加法器,可以看下。 电路结构 设计文件 1位加法器 librar…

Python-VBA函数之旅-iter函数

目录 一、iter函数的常见应用场景: 二、iter函数使用注意事项: 三、如何用好iter函数? 1、iter函数: 1-1、Python: 1-2、VBA: 2、推荐阅读: 个人主页:神奇夜光杯-CSDN博客 …

《深入Linux设备驱动程序内核机制》学习笔记-第4章

前言 本文是《深入Linux设备驱动程序内核机制》的读书笔记,本文因为是读书笔记所以抄写引用了该书中的大量内容,写读书笔记的目的是在写作的过程中加深对书中内容的理解。 建议读者直接阅读《深入Linux设备驱动程序内核机制》,这本书是Linu…

word导出或另存为pdf图片不清晰问题解决方案

问题描述: 使用word 2019导出pdf时图片不清晰,即使我已经在“选项 → \to →高级 → \to →图片大小和质量 → \to →不压缩文件中的图像 ”选项卡中关闭掉了图片压缩依然无效。 解决方案: 利用word foxit pdf 软件打印的方案转pdf。 &…

SpringBoot3 + Kotlin + mybatis-plus + Swagger3后端开发样例

前言: Kotlin 是一种在 JVM(Java 虚拟机)、Android 和浏览器端运行的静态类型编程语言。以下是关于 Kotlin 的总结介绍: 1、语言特性: 简洁性:Kotlin 旨在提供简洁且安全的代码,同时保持与 Jav…

学校开展第二届教学名师沙龙

四川城市职业学院讯 4月23日下午,党委教师工作部(质量部)、教师发展中心组织开展了以“大力弘扬教育家精神,建设高质量高水平教师队伍”为主题的第二届教学名师经验分享沙龙活动。全校12名入选学校教学名师(名辅导员…

vue3+Echarts+Nodejs实现动态数据可视化

最近在做毕设的后台管理系统,刚好需要做数据动态可视化的功能,就来记录一下具体的实现方式吧! 在开始之前就不阐述用vue创建项目的具体步骤了,主要详细讲解一下vue3、echarts和nodejs三者之间是如何实现数据的动态显示的&#xf…

kafka大数据采集技术实验(未完待续)

Kafka环境搭建 下载地址:https://link.zhihu.com/?targethttps%3A//kafka.apache.org/downloads解压启动zookeeper bin/zookeeper-server-start.sh config/zookeeper.properties需要注意的是 : " c o n f i g / z o o k e e p e r . p r o p e r t i e s &q…

探秘三维地形瓦片服务:流畅展现全球地貌的秘密揭秘

想象一下,如果我们能将全球地形一次性清晰地呈现在我们的电脑屏幕上,那将是怎样的场景?即使拥有比大多数人性能更强悍的电脑,也会忍不住说一句:“卧槽,卡死了”!那么,要在电脑中流畅…

linux驱动-CCF-0基础

1. 时钟设备 晶振:提供基础时钟源的(可分为有源晶振、无源晶振两种); PLL: 用于倍频的锁相环; mux: 用于多路时钟源选择; Divider: 用于分频的; gate: 用于时钟使能的与门电路等 注册函数…

聚焦数字文创产业!国际数字影像产业园落地成都金牛区

聚焦数字文创产业!又一成都文创产业园落地成都金牛区。在数字文创浪潮中,成都金牛区凭借其前瞻性的视野和战略性的布局,成功吸引了又一成都文创产业园“国际数字影像产业园”的落地,为区域经济的增长和文化产业的升级注入了新的活…

C语言实现二叉树

二叉树 1、完全二叉树的递归创建 #define N 6 typedef char data_type; typedef struct bitree{ int n; data_type data; struct bitree *lchild; struct bitree *rchild; }bitree_t; //创建二叉树 bitree_t *create_bitree(int n){ bitree_t *rootNULL; root(bitree_t*)mallo…

提示词优化的自动化探索:Automated Prompt Engineering

编者按: 作者在尝试教授母亲使用 LLM 完成工作任务时,意识到提示词的优化并不像想象中简单。提示词的自动优化对于经验并不丰富的提示词撰写者很有价值,他们没有足够的经验去调整和改进提供给模型的提示词,这引发了对自动化提示词…

node和go的列表转树形, 执行速度测试对比

保证数据一致性,先生成4000条json数据到本地,然后分别读取文本执行处理 node代码 node是用midway框架 forNum1:number 0forNum2:number 0//执行测试async index(){// 生成菜单列表// const menuList await this.generateMenuList([], 4000);const men…

C++ | Leetcode C++题解之第47题全排列II

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<vector<int>> permuteUnique(vector<int>& nums) {dfs(nums, 0);return res;} private:vector<vector<int>> res;void dfs(vector<int> nums, int x) {if (x num…

js的算法-插入排序(直接插入排序)

插入排序 插入排序是一种简单直接的排序方法&#xff0c;其基本思想是每次将一个待排序的记录按其关键字大小插入到前面已经排好序的子序列&#xff0c;直到全部记录插入完成。由插入排序的思想可以引申出三个重要的排序算法&#xff1a; 直接插入排序、折半插入排序和希尔排序…

【书生浦语第二期实战营学习作业笔记(二)】

书生浦语第二期实战营学习作业&笔记(二) 操作文档&#xff1a;https://github.com/InternLM/Tutorial/blob/camp2/helloworld/hello_world.md 基础作业 &#xff1a; 使用 InternLM2-Chat-1.8B 模型生成 300 字的小故事&#xff1a; 八戒部署&#xff08;笔记&#xff0…

【Linux系统编程】第九弹---权限管理操作(下)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、目录权限 2、粘滞位 总结 1、目录权限 首先提出一个问题&#xff0c;删除一个文件需要什么权限呢&#xff1f;&#xff1f…

竞赛 基于大数据的社交平台数据爬虫舆情分析可视化系统

文章目录 0 前言1 课题背景2 实现效果**实现功能****可视化统计****web模块界面展示**3 LDA模型 4 情感分析方法**预处理**特征提取特征选择分类器选择实验 5 部分核心代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据…