当前位置: 首页> 教育> 锐评 > 企业网厅_b2b网站20180409_seo 的原理和作用_免费文件外链网站

企业网厅_b2b网站20180409_seo 的原理和作用_免费文件外链网站

时间:2025/7/13 7:16:23来源:https://blog.csdn.net/2301_81758005/article/details/142899182 浏览次数:0次
企业网厅_b2b网站20180409_seo 的原理和作用_免费文件外链网站

一、进程状态

CPU执行进程代码不是把进程代码执行完毕,才开始执行下一个,而是给每一个进程预分配一个时间片,基于时间片,进行调度轮转。 

并行和并发

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。

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

时间片

Linux/windows民用级别的操作系统是分时操作系统,调度任务追求公平。

运行(进程放在运行队列中)

只要进程在运行队列中,该进程就叫做运行状态,可以被CPU随时调度 。

阻塞(进程放在设备的等待队列中)

例如进程程序里面有scanf函数,其底层封装访问键盘的接口,对外部设备进行读取信息的操作,当键盘中没有信息输入的时候,进程被放置到外设结构体的等待队列中,这个过程便就是阻塞的过程。

挂起

挂起的背景:内存资源严重不足的时候。

例如在内存中,多个进程处于阻塞状态时,会被换出到磁盘中,当访问到外部设备信息的时候,再被换入到磁盘中(磁盘中有个swap分区专门进行换出换入操作)从而用时间换空间,因为换入换出的本质是IO

二、Linux进程的状态

下面的状态在kernel源代码里定义:

/*
* 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 */
};

R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。 

S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠(interruptible sleep))。

 该进程可以被杀掉:

 

D磁盘休眠状态(Disk sleep):有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。(防止数据丢失)

T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。

Z(zombie)-僵尸进程

僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。(通俗点说就是,子进程退出了,子进程的代码和数据都被释放,但是父进程仍然管理着子进程的PCB,这使得内存资源被无效占用,从而引发了系统层的内存泄漏)

僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态

所以需要父进程读取子进程的信息后,子进程退出才行。

补充说明:

进程退出时,代码不会被执行了,首先可以立即释放的就是进程对应的程序信息数据。进程退出,要有退出信息(进程的退出码)保存在自己的task_struct内部,管理结构task_struct必须被操作系统维护起来,方便用户未来进行获取进程退出的信息。

进程创建时,先创建内核数据结构再添加代码和数据。进程退出时先释放代码和数据,然后就是内核数据结构。将代码数据释放,内核数据结构维护的状态就是僵尸状态。

创建维持30秒的僵死进程例子

#include <stdio.h>
#include <stdlib.h>
int main()
{pid_t id = fork();if(id < 0){perror("fork");return 1;}else if(id > 0){ //parentprintf("parent[%d] is sleeping...\n", getpid());sleep(30);}else{printf("child[%d] is begin Z...\n", getpid());sleep(5);exit(EXIT_SUCCESS);}return 0;
}

僵尸进程危害

进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。可父进程如果一直不读取,那子进程就一直处于Z状态

维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,换句话说,Z状态一直不退出,PCB一直都要维护

一个父进程创建了很多子进程,就是不回收,就会造成内存资源的浪费。因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!

孤儿进程

父进程先退出,子进程就称之为“孤儿进程。

孤儿进程被系统接管,从而变成后台进程。之所以要被系统接管是因为要回收它的PCB。

三、进程优先级

基本概念

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

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

查看系统进程

UID : 代表执行者的身份(表面进程是谁启动的,linux下一切皆文件,文件会记录下拥有者,所属组和对应的权限,所有操作都是进程的操作,进程会记录是谁启动的我)
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :代表这个进程的nice值

优先级

PRI and NI

PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高。

那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值。

PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice;这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行。所以,调整进程优先级,在Linux下,就是调整进程nice值。nice其取值范围是-20至19,一共40个级别。

pri(最终)=pri(default80)+nice

nice范围:[-20,19]40个数字

需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。可以理解nice值是进程优先级的修正修正数据

用top命令更改已存在进程的nice:进入top后按“r”–>输入进程PID–>输入nice值

四、进程切换

前提:

时间片到了,进程就要切换,Linux是基于时间片调度轮转的,一个进程在时间片到了的时候,不一定跑完了,可以在任何地方重新调度切换。

感性理解

切换就是保存上下文数据和恢复上下文数据的过程

切换过程的理解

进程在运行时,会有很多的临时数据,都在cpu的寄存器中保存。其中eip(pc)中保存的是当前正在执行指令的下一条指令的地址。ir是指令寄存器,保存的就是正在执行的指令。CPU内部的寄存器的数据,是进程执行时的瞬时状态信息数据(上下文数据)。CPU里面有很多寄存器,但是寄存器不等于寄存器里面的数据。

进程切走时:将相关寄存器的内容保护起来;切回时:将历史保存的寄存器数据,恢复到寄存器中。中间所需的保护代码的容器并不在CPU内部(可以这么理解:进程的上下文寄存器数据,被保存到了当前进程的PCB中)。所以每次切换时,每次保存完上下文数据的时候CPU都是全新的。

Linux第一代内核: 

五、Linux的调度算法

一开始,active指针指向array[0],expired指针指向array[1]。

优先级

普通优先级:100~139(我们都是普通的优先级,想想nice值的取值范围,可与之对应)

实时优先级:0~99

活动队列

1、时间片还没有结束的所有进程都按照优先级放在该队列。
2、nr_active: 总共有多少个运行状态的进程
3、queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下标就是优先级

从该结构中,选择一个最合适的进程的过程:

1. 从0下标开始遍历queue[140]
2. 找到第一个非空队列,该队列必定为优先级最高的队列
3. 拿到选中队列的第一个进程,开始运行,调度完成!
4. 遍历queue[140]时间复杂度是常数!但还是太低效了!

5、 bitmap[5]:一共140个优先级,一共140个进程队列,为了提高查找非空队列的效率,就可以用5*32个比特位表示队列是否为空,这样,便可以大大提高查找效率!

过期队列

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

active指针和expired指针

1、active指针永远指向活动队列
2、expired指针永远指向过期队列
3、可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在的。
4、没关系,在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了一批新的活动进程!

Linux链式结构

这样设计的好处是:一个进程,既可以在全局链表中,又可以在任何一个其他数据结构中,只要加结点字段即可。 

总结:

在系统当中查找一个最合适调度的进程的时间复杂度是一个常数,不随着进程增多而导致时间成本增加,我们称之为进程调度O(1)算法

关键字:企业网厅_b2b网站20180409_seo 的原理和作用_免费文件外链网站

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: