linux进程概念

news2024/11/18 13:37:09

目录 

1、进程的基本概念

2、进程控制块 - PCB

task_struct内容分类

3、查看进程

通过ps命令查看进程

通过proc查看进程

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

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

6、进程状态

操作系统进程状态

linux进程状态

僵尸进程

孤儿进程

僵尸进程的危害

进程状态总结

7、进程优先级

基本概念

查看系统进程 

PRI and NI

通过top命令修改进程优先级(ni)

8、linux中的四个重要概念


1、进程的基本概念

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

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

  • 假设我们在磁盘上写了一个test.c的文件代码,最终经过编译链接形成test.exe可执行程序。这个可执行程序也是一个文件,当前在磁盘当中,根据冯诺依曼体系,如果我们想要运行这个可执行程序,我们就需要将其从外设(磁盘)加载到内存中,然后CPU再和内存交互。而加载的过程就叫做此程序运行起来了,但是我们并不能说其为进程,因为加载到内存中只不过是将代码和数据加载进去,此程序只是被搬到内存中,它依旧是一个程序。

 操作系统里面可能同时存在大量的进程,所以操作系统要把所有的进程管理起来,对进程的管理本质就是对进程数据的管理。这里就又用到了结构体和数据结构。

⭐:严格意义上的进程=可执行程序+该进程对应的内核数据结构

 2、进程控制块 - PCB

操作系统里面存在大量的数据,操作系统需要把所有的进程管理起来,而对进程的管理,本质就是对进程数据的管理,依旧是先描述,再组织。

先描述:

  • 当一个程序加载到内存时,除了加载了代码和相关数据,操作系统还要为了管理该进程创建对应的数据结构,而在linux操作系统中描述进程是用一个叫task_struct的结构体,进程的所有属性数据全部放入此结构体中。当我们有多个进程的时候,相对应的操作系统也就创建多个task_struct结构体。

再组织:

  • 这里我们将所有的task_struct用双链表进行链接起来,此时对进程的管理也就变成了对内核数据结构的管理。

在操作系统中我们把描述进程的结构体叫做PCB(进程控制块),而linux操作系统下的进程控制块叫做struct task_struct,以此来描述进程结构体

task_struct内容分类

task_struct主要包含以下内容:

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

 3、查看进程

我们现在创建一个可执行程序mytest,它现在位于磁盘上,现在我们将程序运行起来,此时程序就变成了一个进程。

我们该如何查看现在的进程呢,主要有以下两种方法:

  • 通过ps命令查看进程
  • 通过proc查看 

通过ps命令查看进程

ps ajx | grep 'mytest'

ps ajx命令会把你系统中所有的进程显示出来,而随后的命令其目的是只把名为mytest的进程显示出来:

此刻我们发现我们要的是mytest进程,但为什么又出现了grep的进程呢?

  • 我们自己写的代码,编译成为可执行程序,启动之后就是一个进程,同样别人写的代码,启动之后也是一个进程。例如先前学到的ls、pwd、touch、grep、chgrp……指令,这些指令就是别人写的,存在目录/usr/bin/里头, 这些指令在执行后也会成为进程,这也就是为什么上面会把grep显示出来。

那么我们如何只显示mytest的进程呢?

输入下面指令:

ps ajx | grep 'mytest' | grep -v grep

此命令就是把带有grep字符的进程屏蔽掉,只展现出来mytest进程。

通过proc查看进程

我们都知道在根目录下有许多的路径:

我们要注意上面的proc目录,它是一个内存文件系统,里面存放的是当前系统实时的进程信息。下面我们进入此目录里面看看:

 每一个进程在系统中都会存在一个唯一的标识符,就如同每个学生都有一个自己的专属学号一样,而这个唯一标识符在linux中称为pid(process id),而上面框框所圈住的蓝色数字即为进程的pid。 

我们可以查看进程的所有title列名称,我们输入下面指令:

ps ajx | head -1

这一行显示出来的就是所有的属性名,提取好了属性,我们就可以创建mytest的进程,然后显示mytest进程的具体信息。

ps ajx | head -1 && ps ajx | grep 'mytest' | grep -v grep

我们知道proc存放的是当前系统实时的进程信息,现在我们已经知道了进程mytest的pid(13261),下面我们就在proc目录里面查询一下:

我们知道proc里面存放的是进程的实时信息,那如果我们结束进程mytest,那么我们就不能在proc里面查询到mytest了:

而当我们再次运行起mytest程序时,结果如下:

此时我们会发现mytest先前的pid失效了,由此我们知道,当一个相同的程序重新启动那么其就是一个新的进程,会给该进程重新分配一个pid。 

下面我们具体来看一下进程的两个属性:

ls/proc/27120 -al

  • cwd表示进程当前的工作路径。
  • exe表示进程对应的可执行程序的磁盘文件。

如果我们用fopen创建一个文件,那么此文件默认就在当前路径,而当前路径指的就是当前进程所在的路径,进程会自己维护当前路径

⭐:如pid,当前路径等这些都是进程的内部属性,都在进程的进程控制块PCB(task_struct)结构体中。

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

通过系统调用获取pid需要用到系统调用函数getpid和getppid来分别获取进程pid和父进程ppid。

下面我们来看一下系统调用函数:

man 2 getpid

 

下面我们运行一下该程序:

我们可以看到mytest进程的pid为32321,下面我们通过ps命令来查看该进程的相关信息,验证一下结论是否正确。

那么我们如何杀掉进程呢??? 

  • 按下ctrl + c
  • 使用命令:kill -9 pid

下面我们来看一下进程的ppid:

我们可以看到当我们每重启一个进程的时候,其pid是会不断的发生变化的,但其父进程ppid不会发生变化。下面我们来看一下其父进程究竟是什么:

 从图中我们可以看到父进程10026就是一个bash,几乎我们在命令行上所执行的所有指令,都是bash进程的子进程! 

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

我们知道,我们创建进程是用 ./可执行程序,那么有没有一些函数调用或者系统调用能让我创建子进程呢?下面我们来认识一下创建子进程的系统调用接口fork:

man 2 fork

下面我们来看一下它的返回值:

 我们可以看到fork有两个返回值,如果子进程创建成功,那么就把子进程的pid返回给父进程,把0返回给子进程,如果创建失败,把-1返回给父进程。

下面我们用测试代码来证明一下:

上面是我们的测试代码,我们知道如果按照常规思路,上面的printf应该只执行一次,下面我们看一下测试结果:

我们看到printf执行了两次,这完全不符合C语言的逻辑!!!!

下面我们再来看一下更奇怪的现象:

测试代码:

测试结果:

我们可以看到同一个id值,使用打印,没有修改,却打印出来了不同的值!!!

下面我们来验证一下是否创建了子进程:

我们知道这段代码会分别按照父进程和子进程的代码逻辑执行两次,下面我们来看一下执行结果:

我们可以看到执行结果和我们预期的一样。

结论:

  • fork之后,父进程和子进程会共享代码,一般都会执行后续的代码—解释printf为什么会打印两次的问题
  • fork之后,父进程和子进程返回值不同,可以通过不同的返回值,判断,让父子执行不同的代码块。

⭐:两个重要问题:

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

  • 一个父进程可能有多个子进程,但一个子进程只能有一个父进程。父进程必须有标识子进程的方案,从而控制子进程。而这个方案就是给父进程返回子进程的pid。
  • 子进程最重要的是要知道自己创建成功了,同时子进程找父进程的成本非常的低,只需要getppid即可,所以我们只需要给子进程返回0即可。

2.为什么fork会返回两次?

在我们fork以后,os使系统多了一个进程。

  • 父进程:task_struct+进程代码和数据
  • 子进程:task_struct+进程代码和数据
  • 子进程的task_struct对象内部的数据基本上是从父进程继承下来的。
  • 子进程和父进程执行相同的代码,fork之后,父子进程代码共享,而数据要各自独立。也正是数据的不同使其有不同的返回值从而执行不同的代码。

当我们调用一个函数,当这个函数准备return的时候,这个函数的核心功能已经完成,子进程被创建,并将子进程放入运行队列, 此时父子进程都存在且代码共享,那么return就顺理成章运行两次,自然也就有了两个返回值。

6、进程状态

进程状态本质上是一个整数,在进程的task_struct中(int status)

  • 进程状态反映进程执行过程的变化。这些状态随着进程的执行和外界条件的变化而转换。在三态模型中,进程状态分为三个基本状态,即运行态,就绪态,阻塞态。在五态模型中,进程分为新建态、终止态,运行态,就绪态,阻塞态。

下面我们将以面到点,先从操作系统层面讲进程状态,最后细化到linux层面。

操作系统进程状态

对于操作系统,我们分运行、终止、阻塞、挂起这四个状态来进行讲解,当我们对这四个状态了解过后,就会对上图有清晰的认知。

1.进程运行:

  • 进程只要在运行队列中就叫做运行态,运行态代表进程已经准备好,随时都可以被调度。

2.进程终止:

  • 进程终止态指的是进程还在,只不过永远不运行了,随时等待被释放!

问:进程都已经终止了,为什么操作系统不立马释放对应的资源,而要去维护一个终止态?

  • 释放也要花费时间,操作系统是一个“大忙人”,等操作系统闲暇的时候它就会把进程给释放了。

3.进程阻塞:

  • 一个进程在使用资源的时候可不仅仅是在申请CPU资源,进程可能申请更多的其他资源,如:磁盘、网卡、显卡、显示器资源、声卡/音响等等。
  • 如果我们申请CPU资源暂时无法得到满足,我们进程是需要在CPU的运行队列中进行排队的,那么同样的当我们申请其他慢设备的资源也是需要排队的!!!(task_struct在进程排队)。
  • 当进程访问某些资源(磁盘、网卡等),该资源如果暂时没有准备好或者正在给其他进程提供服务,此时:

             1. 当前进程要从runqueue中移除

             2. 将当前进程放入对应设备的描述结构体中的等待队列中。

           (操作系统对进程的管理任务)

结论:进程等待某种资源(非CPU),资源没有就绪的时候,进程需要在该资源的等待队列                  中进行排队,此时进程的代码并没有运行,进程所处的状态叫做阻塞。

4.进程挂起:

  • 挂起和阻塞有点类似,挂起最终也是卡住了,不过挂起和阻塞在操作系统的定义上还是有点区别。进程挂起就不会申请CPU资源,也就意味着该进程此时处于一个非运行状态。

 上面面临了一个问题:如果进程过多而导致内存不足怎么办??

  • 此时操作系统就要帮我们进行辗转腾挪,将那些短期内不会被调度(你等的资源,短期内不会就绪)进程,它的代码和数据依旧在内存中!就是白白的浪费空间!此时os就会把该进程的代码和数据置换到磁盘上!如下图所示:

  • 结论:当我们把短期内不会被调度的进程的代码和数据置换到磁盘中后,释放掉这块空间,此时内存就多出来了这块空间的容量,可以短期内让其它进程使用。操作系统通过此种方法让进程只在内存中留下PCB,剩下的代码和数据全部置换到磁盘上面(swap分区),这样的进程就叫做进程挂起。(往往内存不足的时候,伴随着磁盘被高频率访问

linux进程状态

linux操作系统的源代码当中对于进程状态有如下定义:

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
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 */
};

1.运行状态-R

  • 一个进程处于运行状态(running),表明这个进程要么是在运行中,要么是在运行队列里。

示例:

此程序编译运行以后进入死循环,此程序也没有访问其他外设资源,此进程一直在cpu的队列里面,下面我们来看一下进程的状态:

我们看到当我们的代码不访问外设,只访问cpu资源,那么就是R状态。

2.浅度睡眠状态-S

示例:

我们运行此代码,然后查看进程状态:

 我们运行了此进程以后,为什么显示出来的是S睡眠状态呢?

  • 我们这里执行了printf语句,打印信息我们需要访问外设(显示器),但是想要访问外设的进程很多,操作系统会把你的进程PCB放到显示器的等待队列里面,当轮到你的时候操作系统会把你唤醒 ,此时我们就可以打印了。这就是S睡眠状态,对应的就是上文操作系统层面上的阻塞状态

⭐:S睡眠状态又叫做浅度睡眠可中断睡眠

  • 浅度睡眠:当进程处于S状态,它可以随时被操作系统唤醒。
  • 可中断睡眠:当进程处于S状态,它可以随时被kill掉。

 3.深度睡眠状态-D

  • D状态也是一种阻塞状态,只不过这种阻塞状态与传统阻塞状态不同。在linux中,当我们等待的是磁盘资源,那么我们进程阻塞所处的状态就为D状态。

实例分析:

  • 假如我们内存中有一个500MB大小的进程,我们需要将进程的代码和数据写到磁盘上,磁盘在写入这500MB的过程中,进程在内存中默默的等待磁盘完工,此时进程所处的状态就为S状态,进程不会被运行,等待磁盘资源就绪给其反馈结果。但是在进程等待的过程中,如果内存中的进程越来越多,操作系统也就越来越忙,S状态进程只占内存不干事,操作系统就会将它kill掉(一般服务器压力过大,OS会终止用户的进程)。这时候当磁盘写完数据(不管写入成功还是失败)呼叫进程的时候发现进程已经不在了。

无论磁盘读取成功与否,此数据都失效了,因为对应的进程被OS杀掉了,那么谁来背这个锅 ?

  • 操作系统:当内存不够,OS有权去杀掉进程,这是属于OS的权利。
  • 进程:进程将数据给磁盘是进程应该做的,进程需要等待磁盘的反馈结果。
  • 磁盘:磁盘也只是做了它该做的,将数据写到磁盘里面。

综上:OS、进程、磁盘这三者都没有错误,所以设计操作系统的人为了使这个进程不被操作系统kill掉,于是就设计出了D状态,也就是深度睡眠状态,也叫做不可被中断睡眠。此时进程在等待磁盘的过程中就由浅度睡眠S转变为深度睡眠D,就不会被OS杀掉,我们想要解决掉D状态,就需要我们关机重启或者拔电源解决。

 4.死亡状态-X

  • 死亡状态是一个返回状态,当一个进程的退出信息被读取后,该进程所申请的资源就会立即被释放,该进程也就不存在了,你不会在任务列表里看到这个状态。

 5.僵尸状态-Z

  • 假设张三和李四一起外出跑步,跑着跑着李四突然倒了,张三赶紧打110和120,医生判定李四已无生命迹象,此时医生任务已经完成,但警察还要调查李四的死因,是他杀还是自杀。在警察调查李四的死因过程中,李四所处的状态就为僵尸状态

⭐:当linux中的一个进程退出的时候,一般不会直接进入X状态(资源可以立马被回收), 而是进入Z状态。

为什么进程要进入Z状态呢??

  • 进程被创建出来,一定是因为有任务让这个进程执行,当进程退出的时候,一般需要把进程的执行结果告知给父进程或者OS以此让我们得知任务的完成结果。
  • 进程进入Z状态,就是为了维护退出信息,可以让父进程或os读取(通过进程等待来进行读取)。最后才能进入X状态。

6.暂停状态 - T/t

  • 在Linux中,我们可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

示例:

如果我们想要将进程暂停,输入下面命令:

kill -l

 我们可以看到第18个信号是使进程继续,第19个信号是使进程暂定。

  • 暂停进程: kill -19 "进程pid"

  • 继续运行进程:kill -18 "进程pid" 

  • t也是暂停状态,和T不一样的是它代表的是进程被调试的时候,遇到断点所处的状态,追踪状态。 

僵尸进程

前面我们提到过,当一个进程正在等待其退出信息被读取的的状态叫做僵尸状态。处于僵尸状态的进程叫做僵尸进程。

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

下面我们来创建一个维持30s的僵尸进程实例:

运行该代码以后,我们可以通过下面指令来实现对进程信息的检测:

while :; do ps ajx | head -1 && ps ajx | grep process | grep -v grep; sleep 1; echo "—————————————————————————————————————————————————————————————————"; done

 通过对上面进程的pid和ppid观察,我们得知,pid为26726的是父进程,pid为26727的是子进程。运行5s后子进程退出变为Z状态。此时进程就变为了僵尸进程。

孤儿进程

我们将僵尸进程代码修改为如下代码:

运行此程序查看进程信息:

通过上图我们可以看出子进程为8133,父进程为8132,可是当我们父进程8132退出的时候,父进程为什么没有变成僵尸状态呢??

  • 父进程8132的父进程是bash,bash会自动回收它的子进程,也就是这里的父进程8132。这里看不到僵尸进程是因为父进程8132被它的父进程bash回收了。

子进程退出的时候父进程要通过某种方式回收子进程,但这里的父进程8132被bash自动回收,但这里的子进程8133还没退出,如果我们的子进程8133退出,那谁来回收子进程呢??

  • 这里操作系统扮演了干爹的角色,如果父进程提前退出,那么子进程就会被1号进程(操作系统)领养,我们把这种被领养的进程称为孤儿进程

⭐:当我们父进程退出的时候,状态由S+变为S,S+代表的是前台进程,S代表的是后台进程,并且这里使用ctrl+c并不能结束进程,我们需要手动kill进程。

僵尸进程的危害

  • 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态?是的!
  • 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存task_struct(PCB)中,换句话说, Z状态一直不退出, PCB一直都要维护?是的!
  • 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!这样就会导致内存泄漏

进程状态总结

  • 进程在操作系统中的运行状态,对应linux操作系统中的运行状态R
  • 进程在操作系统中的终止状态,对应linux操作系统中的僵尸状态Z和死亡状态X
  • 进程在操作系统中的阻塞状态,对应linux操作系统中的浅度睡眠状态S和深度睡眠状态D
  • 进程在操作系统中的挂起状态,对应linux操作系统中的S、D、T状态。

7、进程优先级

基本概念

🚩优先级vs权限

  • 优先级是进程获取资源的先后顺序。比如你中午去食堂吃饭排队,排在前面优先级高先打到饭,排到后面优先级低,后打到饭。但是总能吃到饭。
  • 权限是你能不能的问题。比如我们想要看某部电影,但需要开通VIP,普通用户不能观看,因为你没有那个权限。

🚩为什么要存在优先级:

  • 在我们系统里面,进程占大多数,而资源始终是少数。CPU只有一个,可是进程有n个,在系统里面竞争资源是常态,所以我们要存在优先级来确定前后。

🚩总结:

  • cpu资源分配的先后顺序就是指的进程的优先级。
  • 优先级高的进程有优先执行权利。配置进程优先级对多任务环境的linux很有用,可以改善系统性能。
  • 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

查看系统进程 

在linux或者unix系统中,我们运行一个无限循环的process文件,并用ps –l命令则会类似输出以下几个内容:

ps -l

 下面我们解释一下上面的几个重要信息:

  • UID : 代表执行者的身份
  • PID : 代表这个进程的标示符
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的标示符
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行
  • NI :代表这个进程的nice值

PRI and NI

Linux下用PRI(priority)和NI(nice)来确认优先级:

  • PRI即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高,越大代表进程优先级越低。
  • NI就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值只能通过修改ni值来更改优先级。
  • Linux下默认进程的优先级是80
  • PRI值越小越快被执行,那么加入nice值后,将会使PRI变为:PRI(new)=PRI(old)+nice.当我们每次设置优先级,这个old优先级都会恢复为80。
  • 当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行。所以,调整进程优先级,在Linux下,就是调整进程nice值。
  • nice其取值范围是【-20,19】,所以pri的取值范围是【60,99】。分别40个级别。

通过top命令修改进程优先级(ni)

修改进程优先级就是在修改ni值,这里有两种方法:

  • 通过top命令修改进程的nice值。
  • 通过renice命令修改进程的nice值。

⚠:需要注意的是进程的优先级不能随意修改,它会打破调度器平衡。需要我们非要修改进程优先级,就需要使用超级用户root修改。

我们这里只讨论一种方法:使用top命令修改进程优先级

1.创建进程process,修改其优先级:

2.输入sudo top命令:

 

3.按下' r '键,此时会要求你输入待调整nice值的进程的PID

 

4.输入后按下回车,此刻会要求你输入调整后的nice值

 

5.修改后,我们再用ps - al查看是否已经修改:

我们再次修改process的优先级:

⭐:linux不允许无节制的修改优先级,根据我们前面所学到的知识我们知道,尽管我的ni值设置为-100,但是ni最低是-20。而PRI = PRI(old)+nice = 80 - 20 = 60。我们每次设置优先级,old优先级都会恢复成80,这也正是为什么我们后续把ni设置为10,而PRI变成90的原因。

8、linux中的四个重要概念

🚩竞争性

  • 系统进程数目众多,而CPU资源只有少量甚至一个,所以进程之间是具有竞争属性的,为了高效完成任务,更合理竞争相关资源,便就有了优先级。

🚩独立性

  • 多进程运行,需要独享各种资源,多进程运行期间互不干扰。进程运行具有独立性,不会因为一个进程挂掉或者异常,而导致其他进程出现问题。

🚩并行

  • 多个进程在多个CPU下分别同时进行运行,被称为并行。

 🚩并发

  • 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。

⚠:多个进程在你的系统中运行 != 多个进程都在你的系统中同时运行。

  • 不要以为进程一旦占据CPU,就会一直执行到结束,才会释放CPU资源!我们遇到的大部分操作系统都是分时的!!!多个进程在一个运行队列中,操作系统在一次调度周期内会给每一个进程赋予一个时间片的概念!

  • 对于上图,我们假设进程1进入CPU运行,假设操作系统给进程1分配10ms时间,当10ms时间到了,那么进程1就暂停运行,操作系统会把进程1从CPU上剥离下来,然后调度进程2,以此类推............假设运行队列中的进程有5个,且操作系统给每个进程都是分配10ms,那么在1s内,这五个进程平均每个进程要调度20次。

⭐:在一个时间段内,多个进程都会通过切换交叉的方式,让多个代码在一个时间段内都得到推进,而这种现象我们就称作为并发。

补充概念:

🚩抢占式内核

  • 操作系统难道就是简单的根据队列来进行先后调度的吗??有没有可能突然来了一个优先级更高的进程呢???对于正在运行的低优先级进程,如果来个优先级更高的进程,我们的调度器会直接把进程从CPU上剥离,放上优先级更高的进程,这就是进程抢占。

🚩进程的优先级 | 队列

  • 在我们的进程队列中,操作系统是允许不同优先级的进程存在的。且相同优先级的进程,是可以存在多个的。在这里我们借用指针数组的实现方法来实现根据不同的优先级,将特定的进程放入不同的队列中!!!

🚩进程间的切换

  • cpu的内部存在各种各样的寄存器,可以用来临时保存数据。而寄存器又分为可见寄存器和不可见寄存器。当进程在被执行的过程中,一定会存在大量的临时数据会暂存在CPU内的寄存器中。当我们要进行下一个进程而本进程还没结束的时候,我们就需要将本进程的历史数据拿走。

⭐:我们把进程在运行中产生的各种寄存器数据,叫做进程的硬件上下文数据。

  • 当进程被剥离,需要保存上下文数据。
  • 当进程恢复的时候,需要将曾经保存的上下文数据恢复到寄存器中。
  • 上下文数据保存在该进程的task_struct中。

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

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

相关文章

计算机网络-谢希仁-第7版 第1章 概述

计算机网络-谢希仁-第7版 第1章 概述1.011.021.031.071.081.091.101.111.121.131.141.161.171.181.191.201.211.221.241.251.26计算机网络谢希仁版(第七版)答案 1.01 计算机网络可以向用户提供哪些服务? 计算机网络使用户在计算机之间传送数…

【Linux】Linux下的编译器——gcc/g++

💬推荐一款模拟面试、刷题神器 、从基础到大厂面试题:👉点击跳转刷题网站进行注册学习 目录 一、编译的过程 1、预处理阶段 1.1预处理的工作——头文件展开、去注释、宏替换、条件编译 1.2外部定义宏(-D选项) 1.…

会话跟踪技术(Cookie、Session)

目录一、CookieCookie的基本使用发送Cookie获取CookieCookie原理Cookie使用细节二、SessionSession基本使用Session原理Session使用细节三、小结四、登录注册案例会话:用户打开浏览器,访问Web服务器的资源,会话建立,直到有一方断开…

数据结构之堆的应用

系列文章目录 数据结构之堆_crazy_xieyi的博客-CSDN博客 文章目录 前言一、Top-k问题 1.前K个最小数(第k个最小数) 2.前K个最大数(第K个最大数)二、堆排序 1.从小到大排序(建大根堆)2.从大到…

【2022研电赛】安谋科技企业命题一等奖:基于EAIDK-610的中国象棋机器人对弈系统

本文为2022年第十七届中国研究生电子设计竞赛安谋科技企业命题一等奖作品分享,参加极术社区的【有奖活动】分享2022研电赛作品扩大影响力,更有丰富电子礼品等你来领! 基于EAIDK-610的中国象棋机器人对弈系统 参赛单位:西安邮电大学…

硬件开发趋势与技术探索

LiveVideoStackCon 2022 音视频技术大会 北京站将于11月25日至26日在北京丽亭华苑酒店召开,本次大会将延续【音视频无限可能】的主题,邀请业内众多企业及专家学者,将他们在过去一年乃至更长时间里对音视频在更多领域和场景下应用的探索、在实…

2023届C/C++软件开发工程师校招面试常问知识点复盘Part 8

目录52、vector<string>是怎么存储的&#xff1f;53、epoll的底层原理53.1 对比select和poll53.2 ET和LT的工作模式54、进程、线程、协程的理解和他们的通信方式54.1 进程的含义54.2 线程的含义54.3 协程的含义54.4 进程间通信IPC54.5 线程间通信方式55、define宏定义的用…

【JavaDS】优先级队列(PriorityQueue),堆,Top-k问题

✨博客主页: 心荣~ ✨系列专栏:【Java实现数据结构】 ✨一句短话: 难在坚持,贵在坚持,成在坚持! 文章目录一. 堆1. 堆的概念2. 堆的存储方式3. 堆的创建4. 元素入堆5. 元素出堆6. 获取堆中元素二. 优先级堆列(PriorityQueue)1. 优先级队列2. PriorityQueue的特性3. 集合框架中P…

万字启程——零基础~前端工程师_养成之路001篇

目录 什么是前端 什么是后端 前端和后端的区别 前端工程师职责 后端工程师职责 前端的核心技术 HTML CSS JavaScript RESTful结构 特点 HTTP请求方式有哪些 目前最火的前端框架Vue vue优点 vue的响应式编程、组件化 搭建编程环境 什么是编程环境 前端的编程环…

华为云CDN,海量资源智能路由,让内容传输更快一步

华为云CDN,海量资源智能路由,让内容传输更快一步 云服务对于我们生活的影响已经愈发深入&#xff0c;在数字化转型的大背景下&#xff0c;城市管理、公共交通、医疗健康等领域都需要云服务的支持。华为云作为国内知名的云服务平台&#xff0c;以技术强、更可靠、资源多以及帮肋…

基于CentOS 7.9操作系统应用httpd配置本地镜像(本地yum源)

记录&#xff1a;301 场景&#xff1a;配置离线本地镜像源(本地yum源)的三种方式&#xff1a;直接使用iso镜像包配置、使用httpd服务应用iso镜像包配置、使用httpd服务应用rpm包配置。在内网环境或者局域网环境&#xff0c;基于CentOS 7.9操作系统应用httpd配置本地镜像(本地y…

手把手带你玩转Spark机器学习-深度学习在Spark上的应用

系列文章目录 手把手带你玩转Spark机器学习-专栏介绍手把手带你玩转Spark机器学习-问题汇总手把手带你玩转Spark机器学习-Spark的安装及使用手把手带你玩转Spark机器学习-使用Spark进行数据处理和数据转换手把手带你玩转Spark机器学习-使用Spark构建分类模型手把手带你玩转Spa…

Python学习笔记(十三)——编译错误和异常处理

异常和异常类 Python常见错误 语法错误 源代码存在拼写语法错 误&#xff0c;这些错误导致Python 编译器无法把Python源代 码转换为字节码&#xff0c;故也称 之为编译错误。>>> print("我爱山大"} SyntaxError: invalid syntax 运行时错误 • 程序中没有…

Python常用库1:collections,容器数据类型

collections&#xff1a;数据容器 点这里跳到原文地址。预计阅读时长&#xff1a;10分钟未完待续&#xff0c;遇到相关力扣题目&#xff0c;会继续补充~ 文章目录前言一、Collections中的内置函数二、各个函数的使用1. deque1.1 deque的介绍1.2 deque支持的方法1.3 使用deque解…

js-键盘事件

onkeydown:按键被按下 onkeyup:按键被松开 事件绑定的对象&#xff1a;键盘事件一般绑定给可以获取焦点的对象或者document对象 焦点&#xff1a;光标在闪的&#xff1a;比如input标签 如果一直按按键不松手&#xff0c;按键会一直被触发 当&#xff1a;onkeydown连续触发时…

THREE.JS实现看房自由(VR看房)

VR看房一、前言二、基础知识三、场景3.1 网络模型3.2 光照3.2.1 环境光3.2.2 平行光3.2.3 点光源3.2.4 聚光灯3.2.5 半球光四、相机4.1 正交相机4.2 透视相机五、渲染器六、贴图纹理6.1 基础介绍6.2 环境贴图6.3 HDR处理七、拓展7.1 坐标系7.2 控制器7.3 自适应7.4 全屏响应7.5…

C#基础·补丁

文章目录一 命名空间二字符串2.1 System.String类2.2 StringBuilder类三 正则表达式3.1 什么是正则表达式&#xff1f;3.2 查找举例3.3 重复描述字符举例3.4 反义字符3.5 基本语法元字符3.6 定位元字符3.7 择一匹配3.8 分组一 命名空间 二字符串 字符串类 System.String(strin…

python数据分析之numpy

数据分析之Numpy 1、Numpy的数组对象及其索引 import numpy as npimport numpy as npanp.array([1,2,3,4]) print(a) bnp.array([2,3,4,5]) print(b)print(ab)产生数组 从列表产生数组&#xff1a; list_array[1,2,3,4] anp.array(list_array) print(a)从列表传入&#xff…

PCB设计很简单?生产问题才是考验工程师能力的标准!

BOM清单有误 SMT产线&#xff1a;物料封装怎么和PCB焊盘不一致呢&#xff1f;停线排查。 仓库&#xff1a;我是按照BOM清单发的物料。 硬件研发&#xff1a;哎&#xff0c;BOM整理时马虎了。 过孔焊盘问题 “ 连锡问题 产线维修&#xff1a;怎么这么多连锡导致不良的产品&…

【安信可NB-IoT模组EC系列应用笔记⑧】用NB-IoT模组EC系列了解LwM2M协议并接入云平台

文章目录前言一、测试准备1、硬件准备2、云平台准备二、云平台连接1.注册入网2.读取IMSI及IMEI3.利用IMSI及IMEI创建设备4.LwM2M连接云平台设备三、 数据互交1.ATMIPLNOTIFY 通知属性变化2.ATMIPLREADRSP 返回读取结果3.ATMIPLWRITERSP 发送写入结果4.ATMIPLEXECUTERSP 发送执行…