Linux进程 (冯诺依曼体结构 管理 PCB 进程状态 僵尸进程 孤儿进程 运行阻塞挂起状态 进程优先级)

news2024/11/17 2:56:10

文章目录

  • 一.冯·诺依曼体系结构
    • 冯诺依曼结构能干什么?
  • 二.操作系统
    • 概念
    • 结构图(不完整)
      • 为什么要有操作系统?
    • 尝试理解操作系统
    • 管理
    • 结构图(完整)
    • 总结:
  • 三.进程
    • 进程是什么?
    • PCB
      • 为什么要有PCB?
    • Linux中的PCB
    • 进程的task_struct本身内部的属性有哪些?
      • 终止进程
      • 进程创建的代码方式(fork函数)---重操作,轻原理
        • 我们为什么要创建子进程?
        • 多进程
      • task_struct的内容
    • 查看进程(通过/proc查找)
  • 四.进程状态
    • R状态 S状态
    • 状态+中的+是什么意思?
    • T状态 t状态
    • D 状态
    • Z 状态(僵尸进程) 与X 状态
    • 孤儿进程
    • 纯理论:进程的阻塞和挂起,运行
      • 运行状态
      • 阻塞状态
      • 挂起状态
    • 进程切换
  • 进程优先级
    • 什么是优先级?
    • 为什么要有优先级?
    • 如何查看优先级呢?
    • top更改进程优先级
    • nice与renice

一.冯·诺依曼体系结构

在这里插入图片描述
在这里插入图片描述
那么问题就来了,为什么要加一个储存器
直接输入设备–>CPU–>输出设备不好吗?
在这里插入图片描述
短板在输入设备和输出设备,所以加了个存储器
在这里插入图片描述

在计算机里面,离CPU越近,效率越高,造价越贵
存储金字塔
在这里插入图片描述
总结:硬件流动角度,数据层面中:(蓝色箭头)
1.CPU不和外设直接打交道,CPU之和内存打交道
2.外设(输入和输出)的数据,不是直接给CPU的,而是先要放入内存中的

冯诺依曼结构能干什么?

在这里插入图片描述

引例:“你给你的朋友用QQ发送你好!!”的过程

在这里插入图片描述

二.操作系统

概念

开机的操作就是启动操作系统
操作系统是一款软硬件资源管理的软件(比如插个U盘,电脑会显示,可以往U盘里写东西)
操作系统广义的认识:操作系统内核+操作系统的外壳周边程序
狭义:只是操作系统的内核
在这里插入图片描述
windows也可以没有图形化界面的
在这里插入图片描述
安卓的操作系统属于两层
在这里插入图片描述

结构图(不完整)

体系结构的层状划分结构如下
因为操作系统需要硬件的数据,那么每次更新硬件,操作系统获得数据的方式可能跟上一个配对的硬件的方式不一样,那么操作系统就得跟着更新,才能与硬件配对,获取数据
所以操作系统不直接找硬件要相关数据,而是通过驱动层,这样只需要更新驱动就行。(驱动层是独立的,操作系统是核心,更新驱动层肯定比直接更新操作系统方便、安全)
在这里插入图片描述
就比如鼠标,在插入电脑的时候,不能直接使用,是因为驱动层还没有下好。右下角会弹窗显示插入或者鼠标亮了(现在插进去响一声),才能使用。

为什么要有操作系统?

举个例子:
学校有椅子、桌子、粉笔、图书馆里的书、体育器材
角色有老师、保安、校长、教导主任、医生
图书馆里的书需要图书馆管理员管理,椅子桌子坏了找谁报修,学生生病找谁
有了角色的担任,管理起来就会变得方便
操作系统就是对软硬件进行管理
为用户提供提供一个良好(稳定的、安全的、高效的)运行环境
良好的反例是指:用电脑玩原神,10分钟一黑屏,5分钟一重启,就是因为某个硬件造成的。

尝试理解操作系统

管理

管理在生活中无非在做两件事:1.决策 2.执行
比如说不想上今天的早8,这就决策。今天去早8了,这叫执行
在学校层面:校长为管理者,学生是被管理者
在这里插入图片描述

随着被管理的学生的增多,同学的信息也变得非常多,校长很难管理
但是校长会C语言,写了一个关于学生属性的表
在这里插入图片描述
张三的属性就可以用结构体表达出来
在这里插入图片描述
学生有很多人,校长要在5W个学生中找到张三同学,为了节省时间,校长就加了给指针,形成了链表
校长对学生的管理工作(日常),变成了对链表的增删查改(计算机语言)
在这里插入图片描述

于是校长完成了对计算机的建模工作,也就是对学生的管理工作
校长想开除张三,就变成了删除张三的节点
综上所述,管理学生:先把学生的信息描述起来,然后再组织
结论:任何管理:先描述,再组织
引例:C++先提供描述的能力,STL标准库,有各种容器,提供组织的能力
在这里插入图片描述
那么如何管理硬件呢?
比如插入鼠标的一瞬间,进程管理会创建一个关于鼠标的结构体,把鼠标的驱动程序读取到的数据写入该进程(先描述),并以算法(链表等)的形式插入前面的节点后面。(再组织)
在这里插入图片描述

不仅仅是进程管理是这样,只要是与管理相关的都大差不差

结构图(完整)

在这里插入图片描述
谈谈在操作系统上层的部分
作为用户能否直接访问底层硬件吗?
故事:
在这里插入图片描述

隔壁的校长是接触不到张三的,万一张三被拐走了,辅导员找不到人了就是管理人员的失职。要找也是找张三的校长
所以任何访问硬件的操作,都得通过操作系统来做
我们(用户)用C语言中的fopen fclose就经过文件管理,再写进磁盘,绕不过操作系统
同理printf是从显示器上读取数据,scanf是从键盘上读取数据,也是绕不开操作系统的
那用户能否直接访问操作系统呢?
故事:
在这里插入图片描述

在这里插入图片描述
又比如:现在的你改一改操作系统,然后打起了原神,就因为改了操作系统直接蹦掉了。所以用户是不能直接接触操作系统的
上面的故事映射到计算机里面就是:银行中的柜台就是系统调用接口
这样就可以受管控的使用操作系统
在这里插入图片描述
故事进入第二阶段:
作为新时代的青年,准备材料去存钱开户什么的都知道。
但是有一天,来了一个老奶奶要存1000万,但是不会操作
在这里插入图片描述
银行经理就是外壳程序,帮助用户开发等操作
在这里插入图片描述
开发的时候,直接使用系统调用接口,是不具有跨平台性的,在Linux上能跑,windows可不一定能跑
例子:
在这里插入图片描述

总结:

在这里插入图片描述

三.进程

操作系统中,进程可以同时存在非常多
在这里插入图片描述
如何管理这么多进程呢?
先描述,再组织

进程是什么?

假设我们要运行一个名为a.out的可执行文件(程序 = 代码 + 数据)
根据冯诺依曼结构,任何可执行程序都需要进入内存,交给CPU处理
问题来了,下面图中的内存是进程吗?
在这里插入图片描述
可以这样想:如果文件很多,哪个先运行,哪个后运行,什么时候到我运行,堆和栈在哪?
所以:
在这里插入图片描述
操作系统想要管理进程:就得先描述,再组织。
在这里插入图片描述

PCB

PCB全称process control block
PCB在哪里?
在操作系统里,我们电脑或手机开机就是加载操作系统(操作系统也是软件)
在这里插入图片描述
注意的是:操作系统是对PCB的管理,而非对可执行程序管理

为什么要有PCB?

OS要进行管理,就得先描述,在组织

Linux中的PCB

在这里插入图片描述
通常进程排队指的是PCB(struct task_struct)排队,而不是数据
在这里插入图片描述
因为队列的首部的节点是a.out
所以CPU会把a.out的数据弄到CPU中去运行
在这里插入图片描述
总结:调度运行进程,本质就是让进程控制task_struct进行排队
举个通俗点的例子:
同学投简历,大厂会筛选简历,就是对简历(进程)的增删查改,就是对同学(数据)的管理
所以在Linux中进程的概念:进程 = 内核task_struct 结构体 + 程序的代码和数据

进程的task_struct本身内部的属性有哪些?

例子:
Makefile文件

myprocess:myprocess.c
	gcc -o $@ $^
.PHONY:clean
clean:
	rm -f myprocess

myprocess.c文件

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

在这里插入图片描述
如何查看当前的进程呢?
ps axj
ps:查看当前的进程
a:是all的意思
xj:是显示进程的详细信息
axj的顺序可以乱
一个可执行文件和其进程的名字默认是一样的
查看myprocess文件的进程的命令:

ps axj | grep myprocess

会发现有两个关于myprocess的进程,是因为grep本身的进程也被查到了
在这里插入图片描述
显示的每一个信息是什么呢?
显示进程的第一行

ps axj | head -1

在这里插入图片描述
结合起来:
在这里插入图片描述

一个进程,如何知道自己的pid?
前面讲了,用户无法直接访问操作系统
在这里插入图片描述

就需要系统调用接口getpid
在这里插入图片描述
在这里插入图片描述
myprocess.c的代码

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

发现进程中的pid与运行起来的pid一样
在这里插入图片描述

在这里插入图片描述

终止进程

ctrl + C 就是在用户层面终止进程

kill -9 pid可以直接杀掉进程

进程创建的代码方式(fork函数)—重操作,轻原理

发现还有一个getppid,第一个p是parent,第二个p是process,意思是获得当前进程的父进程的id
在这里插入图片描述
看一下父进程id是什么
myprocess.c的代码:

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

跑起来会发现
在这里插入图片描述
其中18839是什么?
是bash
bash是父进程,是命令行解释器,在Linux权限篇中讲了bash是媒婆,派实习生(子进程)的的故事
在这里插入图片描述
创造子进程,因为用户是不能直接去触碰操作系统的,所以用系统调用接口fork。
在这里插入图片描述
myprocess.c的代码如下

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
	printf("process is running,only me!\n");
	sleep(3);
	fork();                                                                                     
	printf("hello world\n");
	sleep(5);
	return 0;
}

运行上面的可执行程序时,运行下面的指令,方便观察进程。-v 是去掉grep的进程

while :; do ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep;sleep 1;done

运行结果:
在这里插入图片描述
可以发现
在这里插入图片描述

我们为什么要创建子进程?

想让子进程和父进程执行不一样的代码
fork会返回两个值
在这里插入图片描述
成功后,子进程的 PID 将在父进程中返回,在子进程中返回 0。 失败时,父进程中返回 -1,不创建子进程。
验证一下fork
process的代码如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
                                                   
int main()
{
    printf("process is running,only me!\n");
    sleep(3);
    pid_t id = fork();
    if(id == -1)  //失败
    {
        return 0;
    }
    else if(id == 0)  //子进程
    {
        while(1)
        {
        	printf("id:%d,I am child process,pid:%d,ppid:%d\n",id,getpid(),getppid());
            sleep(1);
        }
    }
    else  //父进程
    {
        while(1)
        {
                printf("id:%d,I am parent process,pid:%d,ppid:%d\n",id,getpid(),getppid());
            	sleep(2);
        }
    }
    return 0;
}

会发现确实有两个返回值,并且子进程的pid将在父进程中返回
在这里插入图片描述
在这里插入图片描述
于是就出现了两个问题:
1.同一个id,怎么可能即是 == 0,又是 > 0?
2.fork为什么会有两个返回值,并且返回两次
父进程的代码从磁盘中带出来的,子进程只能copy父进程给的代码。
数据上有些独特
在这里插入图片描述

解答一下第二个问题
在这里插入图片描述

多进程

代码如下:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

void RunChild()
{
    while(1)
    {
        sleep(1);
        printf("I am child process,pid:%d,ppid:%d\n",getpid(),getppid());
    }
}

int main()
{
    int i = 0;
    const int num = 5;  //创建5个子进程
    for(i = 0;i<num;i++)
    {
        pid_t id = fork();
        if(id == 0)  //子进程进入
        {
            RunChild();
        }
        sleep(1);  //父进程继续往下走
    }

    while(1)
    {
        sleep(1);
        printf("I am parent process,pid:%d,ppid:%d\n",getpid(),getppid());
    }
    return 0;
}

可以看到进程逐渐变多
在这里插入图片描述

task_struct的内容

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

查看进程(通过/proc查找)

进程的信息也可以通过 /proc 系统文件夹查看
在这里插入图片描述
假设要获取进程的PID==1的程序
直接查看/proc/1文件就行
举个例子:
在这里插入图片描述
进入proc文件,会发现文件里面的目录都是进程,目录名称就是PID
在这里插入图片描述
其中,/proc/PID目录中值得注意的是这两个
第一个表示的是:进程的当前工作路径
第二个表示的是:进程的PCB中会记录自己对应的可执行程序的路径
在这里插入图片描述
把这个进程干掉,发现程序还在跑。(这个图片显示不出来,得自己实验)
因为把磁盘中的文件删掉了,但是进程的代码与数据已经在内存里了
在这里插入图片描述
然后发现cwd和exe没了
在这里插入图片描述
每个进程在启动的时候,会记录自己当前在哪个路径下启动
验证:下面是个简单的文件函数

#include <stdio.h> 

int main()
{
    FILE* fp = fopen("log.txt","w");
    (void)fp;//ignore warning
    return 0;
}

因为是在该目录下运行的进程(a.out),所以默认在该目录下创建log.txt文件
在这里插入图片描述
更改进程的所在路径
用到的函数时chdir
在这里插入图片描述

#include <stdio.h> 
#include <unistd.h>
#include <sys/types.h>

int main()
{
    chdir("/home/sjl");//更改的路径
    FILE* fp = fopen("log.txt","w");
    (void)fp;//ignore waring
    fclose(fp);
    while(1)//显示出进程在运行
    {
        printf("I am a process,pid:%d\n",getpid());
        sleep(1);
    }
    return 0;
}

进程的路径被更改
在这里插入图片描述
会发现在更改的路径下创建log.txt,而运行可执行程序的路径下时没有的
在这里插入图片描述
所以一旦把当前进程的工作目录改了,那么新建对应的一个文件,他就在改过进程的当前目录下

四.进程状态

大概就是下面这种形式
在这里插入图片描述
下面的状态在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状态 S状态

引例:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    while(1)
    {
        printf("I am a process,pid:%d\n",getpid());
    }
    return 0;
}

运行的时候老样子,用以下指令查看进程(可执行程序为a.out)

while :; do ps ajx | head -1 && ps ajx | grep a.out | grep -v grep;sleep 1;done

会发现是S+的状态,是sleep,休眠状态
在这里插入图片描述
然后把printf注释掉

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    while(1)
    {
        //printf("I am a process,pid:%d\n",getpid());
    }
    return 0;
}

再次运行代码,会发现是R+状态,R为进程运行状态
在这里插入图片描述
原因:打印的时候,是往屏幕上打印的,屏幕是外设,CPU运行比外设快很多,CPU需要等显示屏的资源就绪。所以CPU大部分处于S状态,运气好的时候遇到CPU正在执行printf就能查到在R状态
S(休眠状态)本质分为两种:
第一种:进程在等待“资源”就绪(就是上面的例子)
第二种:可中断睡眠(进程处于睡眠的状态(比如sleep函数),但依旧可以被ctrl + c中断)

状态+中的+是什么意思?

代表的是在前台运行还是后台运行
在进程后面加个&代表在后台运行
在这里插入图片描述
运行后你就会发现ctrl + c中止不了
用kill -9 PID终止进程
在这里插入图片描述

T状态 t状态

显示出Linux的信号的指令:-l是list

kill -l

其中9号信号是不是很眼熟,杀掉进程
在这里插入图片描述
上面的信号底层就是宏,跟C语言中的INT_MAX意义差不多
其中19号信号SIGSTOP就是暂停进程
验证:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    while(1)
    {
        sleep(1);
        printf("I am a process,pid:%d\n",getpid());
    }
    return 0;
}

S状态直接变为T状态
在这里插入图片描述
T状态:让进程暂停,等待被进一步唤醒(进程被暂停了,自动变为后台)
18号信号SIGCONT,continue的意思,让进程继续
在这里插入图片描述
调试就是进程暂停
遇到断点处,进程就暂停了
在这里插入图片描述

D 状态

D:Linux系统比较特有的一种状态(disk是磁盘)
因为配置的原因很难演示出来,所以拿图来讲解:
进程要往磁盘中存1个GB的数据
在这里插入图片描述
内存严重不足,操作系统马上被毙掉了,然后看见这个进程悠然自得的SLEEP,一怒之下,把他删了。磁盘找不到了,造成了数据的丢失
在这里插入图片描述
这不行啊,好比说内存是银行的系统,被删掉的进程是银行的转账记录,直接被干没了,造成了上百万的损失。
为了防止这类事情的发生,规定凡是进程要进行数据IO等待外设的时候,进程要将自己的状态设成D状态
D状态:不可被杀,被称为深度睡眠,也被称为不可中断睡眠(S就是浅度睡眠,可被杀和中断)
要唤醒D状态有两种方法:
1.进程自己醒来
2.重启,重启不行就断电

Z 状态(僵尸进程) 与X 状态

一个进程退出的时候,他会把自己退出的信息保留在PCB当中,如果没有人读取PCB中退出进程的消息,这个进程就一直不释放,一般会把代码和数据释放掉,但PCB内容与数据结构会一直存在,直到将来对该进程进行等待,如果不等待就一直处于僵尸状态。如果等待了就会转化为X状态,进而将进程所有的资源全部释放掉
引例:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        //child
        int cnt = 5;
        while(cnt)//子进程运行5次后退出
        {
            printf("I am child,cnt:%d,pid:%d\n",cnt,getpid());
            sleep(1);
            cnt--;
        }
    }
    else 
    {
        //parent
        while(1)//父进程一直不退出
        {
            printf("I am a parent,running always!pid:%d\n",getpid());
            sleep(1);
        }
    }
    return 0;
}

子进程运行结束后就是Z状态(僵尸状态)

在这里插入图片描述
子进程运行完毕,但需要维持自己的退出信息,在自己的进程task_struct会记录自己的退出信息,未来让父进程来读取
在这里插入图片描述
因为X状态释放是一瞬间的,所以查不出来
平时子进程创建出来是要完成任务的,得知道完成任务怎么样(获取子进程退出的信息)
kill不掉僵尸进程的,已经死进程了,杀不了了。

孤儿进程

如果父进程先退出了,那么子进程就是孤儿进程
就是与僵尸进程相反,所以验证的代码也相反:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        //child
        while(1)
        {
            printf("I am child,pid:%d\n",getpid());
            sleep(1);
        }
    }
    else 
    {
        int cnt = 5;
        //parent
        while(cnt)
        {
            printf("I am a parent,cnt:%d,pid:%d\n",cnt,getpid());
            sleep(1);
            cnt--;
        }
    }
    return 0;
}

发现两个S的进程就剩1个S的进程,剩下的那个S进程就是孤儿进程
在这里插入图片描述
问题就来了:父进程都没了,谁去回收孤儿进程?
答:孤儿进程一般都会被1号进程(OS本身)进行领养的
孤儿进程为什么要被OS领养?
答:依旧要保证子进程正常被回收
孤儿进程是可以被kill的
以前我们启动的所有进程(运行C语言代码)。怎么从来没有关心国】过僵尸进程呢?内存泄漏?
答:直接在命令行中启动的进程,他的父进程是bash,bash会自动回收新进程的Z
父进程的一般核心工作都是回收子进程

纯理论:进程的阻塞和挂起,运行

大多数书上的进程状态
在这里插入图片描述

运行状态

在这里插入图片描述
进程在运行队列中,该进程的状态就是R状态。
R状态不是指直接在CPU上去运行,而是值我已经准备好了,可以随时被调度了
一个进程一旦持有CPU,会一直运行到这个进程结束吗?
不会,就比如里面写个死循环,CPU调度就不会走了,其他进程被卡死了。
现实就是打着原神,微信还能收到信息。
是因为当代的内核基于时间片轮转调度的。
假设时间片设置的2毫秒,2毫秒一到,当前进程就会在CPU上剥离下来,插到队列的尾部,然后下一个进程上前,进入CPU
在这里插入图片描述
这样就可以让多个进程以切换的方式进行调度,在一个时间段内同时得以推进代码。就叫做并发
Linux不是这样调度的,上面方法太简单了。只是调度算法的一种。
如果存在两个CPU,就有两个调度队列
在这里插入图片描述
根据不同的进程,放到不同队列,也可以放进两个队列
任何时刻,都同时有多个进程在同时运行,我们叫做并行

阻塞状态

问题:我们在写C语言的时候,用过一个接口scanf,如果我们不输入的话,进程处于什么状态?另外scanf在等待什么资源呢?
测试代码如下:

#include <stdio.h>

int main()
{
    int a = 0;
    scanf("%d",&a);
    printf("a = %d\n",a);
    return 0;
}

会发现是S状态,其实D也算阻塞状态,不过无法演示
在这里插入图片描述
他在等什么呢?在等键盘资源是否就绪,键盘上面有没有被用户按下的按键,按键数据交给进程
键盘上面没数据,进程是不OK,该进程并没有被运行的(R状态),所以一定不在运行队列中
操作系统要对所有的硬件做管理,那么操作系统如何对硬件做管理?
管理肯定离不开先描述,在组织
在这里插入图片描述
一个进程如何等待一个设备呢?
不只是CPU才有等待队列,设备中也有等待队列wait_queue
在这里插入图片描述
演示一下scanf等待键盘资源的总过程:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结:阻塞和运行状态的变化,往往伴随着PCB被连入到不同的队列中
入队列的不是进程的代码和数据,而是进程的task_struct

挂起状态

我们在装系统的时候,会有一个swap分区,大多数情况swap分区是内存的1.5倍2倍,可以自己定义。
当OS中内存吃紧,且有进程处于阻塞状态(暂时不会被调度),那么就把该进程的代码和数据唤出到swap分区中。这样内存就会腾出空间
这种状态叫做阻塞挂起态

在这里插入图片描述

如果该设备又等待就绪了,就会把进程的代码和数据唤入到内存
在这里插入图片描述
这样可以更合理的使用内存资源
还有很多挂起,就绪挂起等。本质都是一样的。
频繁的唤入唤出会导致效率问题。牺牲效率换取空间
不建议把swap分区放大太,因为操作系统会过渡依赖swap分区,一压力大就唤出。要逼着操作系统合理的分配内存
swap分区的位置

ls /proc/swaps

进程切换

CPU内部的所有寄存器中的临时数据,叫做进程的上下文
在这里插入图片描述
寄存器本身是硬件,具有数据的存储能力,CPU的寄存器硬件只有一套
但CPU内部的数据可以有多套,有几个进程,就有几套和该进程对应的上下文数据

进程优先级

什么是优先级?

指定进程获取某种资源(比如CPU)的先后顺序
进程控制模块task_struct中的内部字段有一个或多个整型(比如int prio =)的优先级数字
Linux中优先级数字越小,优先级越高

为什么要有优先级?

进程访问的资源(CPU)是有限的
进程比硬件资源多,显示屏就一个,网页有很多
操作系统关于调度和优先级的原则:分时操作系统,保证了基本公平
如果进程因长时间不被调度,就造成了饥饿问题(比如学生打饭,教导主任差一下队,校长插一下队)

如何查看优先级呢?

引例:

#include <stdio.h>
#include <unistd.h>

int main()
{
	while(1)
    {
    	printf("I am a process,pid:%d\n",getpid());
    	sleep(1);
    }
    return 0;
}

查看当前终端的进程

ps -l

想查看全部终端的进程

ps -al

PRI:进程优先级
NI:进程优先级的修正数据(nice值),新的优先级 = 优先级 + nice
在这里插入图片描述

top更改进程优先级

top

先输入top
在这里插入图片描述
然后输入r
在这里插入图片描述
输入需要调整优先级的PID
在这里插入图片描述
输入100,然后按回车
在这里插入图片描述
会发现优先级是99,不是80+100
在这里插入图片描述
这是因为nice并不能任意调整,是有范围的(-20~19)
如果能随便调,把优先级调很高,就可能会一直运行一个进程,影响了调度的平衡
第二次改的时候不让改了,因为一个进程的优先级是不能频繁改的
在这里插入图片描述
这里切root用户更改,nice的值为6
在这里插入图片描述
发现不是99+6,而是80+6
因为每次调整优先级,都是从80开始的
在这里插入图片描述

nice与renice

这两也可以更改优先级
nice命令格式:nice -n [NI值] [命令]加不加n都行
在这里插入图片描述
renice命令格式:renice [NI值] [PID]
在这里插入图片描述

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

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

相关文章

电销机器人有哪些优势?

首先&#xff0c;电话销售机器人的最大优势在于&#xff0c;它们可以与顾客进行自然对话&#xff0c;这在每个人对机器人的看法上都是一个突破。在每个人的心目中&#xff0c;机器人是不可改变的。冰冷的机械声音会让顾客感到更加厌恶&#xff0c;但事实上并非如此。这种电话售…

Modbus RTU与Modbus TCP协议区别详解

工业自动化领域中&#xff0c;设备之间的数据传输至关重要&#xff0c;而Modbus协议作为一种通信标准&#xff0c;被广泛应用于各类自动化系统。而Modbus协议有两种常见的变体&#xff1a;Modbus RTU和Modbus TCP&#xff0c;下面本文将详细探讨这两种协议的区别。 物理层 Mo…

西安国际数字影像产业园正式落地,开启数字影像产业新篇

随着全球数字经济的蓬勃发展&#xff0c;数字影像产业作为其中的重要组成部分&#xff0c;正吸引着越来越多的企业关注和投入。西安国际数字影像产业园自启动以来&#xff0c;便以独特的魅力正吸引着众多企业争相入驻。作为西安最好的数字产业园&#xff0c;它究竟有何独特魅力…

【电商API接口项目实战分享】项目实战案例一:电商平台零售数据分析

本文以真实案例&#xff0c;带领大家一起学习如何搭建电商零售的用户画像。 “项目介绍” 此次项目数据来自Kaggle&#xff0c;包含了2010年12月1日至2011年12月9日在英国注册的非实体网上零售发生的所有交易。 字段如下: Invoice: 订单编号&#xff0c;每笔交易有6个整数。 …

在IoT中的TCP增强

本文内容节选自一篇系统性文献综述&#xff08;Systematic Literature Review, SLR&#xff09;&#xff0c;标题为“TCP Performance Enhancement in IoT and MANET”&#xff0c;由 Sultana Parween 和 Syed Zeeshan Hussain 撰写&#xff0c;发表在《International Journal …

F4Pan网盘解析获取下载链接的工具系统源码

F4Pan网盘解析获取下载链接的工具系统源码&#xff0c;F4Pan(下称本项目)使用的接口全部来自于官方&#xff0c;无任何破坏接口的行为&#xff0c;本项目所有代码全部开源&#xff0c;仅供学习参考使用&#xff0c;请遵守相关的法律法规&#xff0c;禁止商用&#xff0c;若无视…

【网络安全】本地文件包含及远程文件包含漏洞详解

一、文件包含漏洞概述 1.1 什么是文件包含 开发人员将需要重复调用的函数写入一个文件&#xff0c;对该文件进行包含时产生的操作。这样编写代码能减少冗余&#xff0c;降低代码后期维护难度。 保证网站整体风格统一&#xff1a;导航栏、底部footer栏等&#xff0c;把这些不…

从‘古都’到‘数都’,西安数字产业园龙头正式落地,西安国际数字影像产业园汇聚全球智慧赋能产业升级

在全球数字化浪潮的推动下&#xff0c;数字影像产业正成为科技创新和经济发展的新引擎。作为一座历史与现代交汇的城市&#xff0c;西安正以前所未有的姿态迈向数字经济的新高地。近日&#xff0c;西安数字产业园龙头落地——西安国际数字影像产业园&#xff0c;这不仅是西安市…

MySQL—— Navicat的下载、Navicat连接MySQL的方法、创建表和导入数据

文章目录 Navicat的下载Navicat与MySQL连接创建数据库和表导入数据 Navicat的下载 这里直接提供Navicat 16 版本的下载连接&#xff0c;自取后按照步骤操作即可&#xff1a; 链接: https://pan.baidu.com/s/1JChDTjtvfXKHrE0L2l4A6w 提取码: 1822 Navicat与MySQL连接 点击连…

好酒的五个标准,你知道几个

1.不辣喉 白酒在下咽的过程中不辛辣刺激喉咙&#xff0c;也没有过于灼烧的感觉&#xff0c;口感较为温润&#xff0c;几杯过后&#xff0c;身体就会微微出汗。 2.不上头 白酒在饮用时会较长时间处于微醺的美好状态&#xff0c;头脑清醒&#xff0c;身体放松&#xff0c;不会…

自动化测试常见问题总结

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 选择适合自己的&#xff0c;落地应用&#xff0c;是当下我们应该做的。目前国内的互联网行业&#xff0c;大环境来说&#xff0c;还处在一个快速发展&#xff0c;…

Django异步请求和后台管理实战

项目概述 项目实现Ajax异步请求局部刷新使用XAdmin后台模板提供图片上传接口在明细页应用了富文本编辑器在加载图书信息的时候使用LazyLoad&#xff08;图片懒加载&#xff09; # 环境 asgiref3.7.2 crispy-bootstrap32024.1 defusedxml0.7.1 diff-match-patch20230430 Djang…

内网穿透原理,免费内网穿透(简单使用),公网主动访问内网。

内网穿透的本质就是流量转发&#xff0c;把一个电脑的网卡上的流量数据&#xff0c;转发到另一个网卡的流量数据。 实现原理 网络协议分层就是&#xff0c;物理层&#xff0c;数据链路层&#xff0c;网络层&#xff0c;传输层&#xff0c;应用层。我简单解释一下这些分层协议…

全球情绪分析软件市场规划预测:未来六年CAGR为13.6%

一、引言 随着人工智能和机器学习技术的进步&#xff0c;情绪分析软件市场正迅速成为科技行业的重要组成部分。本文旨在探索情绪分析软件行业的发展趋势、潜在商机及其未来展望。 二、市场趋势 全球情绪分析软件市场的增长主要受企业对客户反馈分析的需求增加、社交媒体监控的…

河底地形的表达形式及与倾斜模型的融合效果

0序&#xff1a; 无人机航测可以解决地表的现状获取&#xff0c;做流域管理&#xff0c;河道管理&#xff0c;生态管理的经常关注河床的变化。其中淤泥的堆积状态是关注的重中之重。 当前对水下高程的测绘&#xff0c;主要是使用无人测量船。设定个轨迹&#xff0c;就和无人机…

03、DQL(数据查询语句)

目录 1、编写顺序 2、基本查询 3、条件查询 4、聚合函数 5、分组查询 6、排序查询 7、分页查询 8、执行顺序 1、编写顺序 SELECT 字段列表 FROM 表名列表 WHERE 条件列表 GROUP BY 分组字段列表 HAVING 分组后条件列表 ORDER BY 排序字段列表 LIMIT 分页参数2、基本查…

手写chatGPT——fetch解析text/event-stream会话流并逐字回显到页面——js技能提升

直接上效果图&#xff1a; 页面分上下两部分&#xff0c;上面是会话界面&#xff0c;底部是提交框。 直接上代码&#xff1a; 解决步骤1&#xff1a;引入vueelementUi <head><meta charset"UTF-8" /><title>Fetch Stream Example</title>…

【java计算机毕设】社团管理系统MySQL springboot vue maven项目设计源码代码+文档 前后端可分离也可不分离

目录 1项目功能 2项目介绍 3项目地址 1项目功能 【java计算机毕设】社团管理系统MySQL springboot vue maven项目设计源码代码文档 前后端可分离也可不分离 2项目介绍 系统功能&#xff1a; 社团管理系统包括管理员、团长、学生三种角色。 管理员功能包括个人中心模块用于修…

ElasticSearch集成webFlux响应式开发

目录 前言 1.Weflux特点&#xff1a; 2.WebFlux简单集成ElasticSearch 2.1 引入基本依赖模块 3.application.yml文件的配置 4.定义Product实体类 5.定义ElasticSearch的数据访问层接口 6.定义Controller 7.启动SpringBoot程序&#xff0c;用postman进行接口测试 前言 We…

mysql的 undo log、redo log、bin log、buffer pool

文章目录 Buffer Pool为什么需要Buffer PoolBuffer Pool 缓存了什么 Redo log为什么需要 redo log&#xff1f;redo log 什么时候刷盘&#xff1f;redo log 文件写满了怎么办&#xff1f; undo log 本文章内容都来自小林coding博主&#xff0c;基于他的文章内容&#xff0c;加一…