欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

马哥 48_02 _Linux操作系统原理 有大用


如下图 

Application就是进程的运行位置

image.png



如下图,

进程是通过双向链表?????来管理的,List(链表),这个链表是有次序的,通过一个可以找到下一个,进程之间?????在内核内部靠一个独立的数据结构Task_Structure 来管理的,这是C语言来描述的一种独立数据组织的数据结构,这个文件整体结合起来也被称为进程描述符

image.png


每一个进程都有进程描述符 (process descriptor),存的是进程的元数据,类似于文件的元数据

每一个进程的描述符彼此之间有关联性的,在内核内部通过一个双向链表,(不必太深究)来进行组织,

在创建一个进程的时候,首先要创建进程描述符,并将其添加到此链表上,

删除一个进程,就要删除进程描述符,,然后内核不能再追踪这个进程了

创建一个进程,除了给进程分配CPU,内存等,还要在内核的内存空间中维护一个进程描述符文件,里面保存的是当前进程的所有相关信息

如下图

是进程描述符的结构,还有许许多多的子结构,

进程描述符从上往下:进程的状态state:ready,stop,stopped,sleeping (interrupt sleeping,uninterrupt sleeping),running(也可以理解为ready),Zombie(僵尸),进程内部可包括多个线程,于是thread_info,usage flags(用法标识),run_list tasks (运行的列表),mm(memory map 内存映射的信息),real_parent  parent(父进程),,tty(tty所关联的终端),,,,thread,fs(file system) file,signal pending(正在传送和接收的信号?正在处理的信号?)

mm_struct 有描述符

thread 有描述符?????

tty_struct 有描述符

fs_struct 有描述符

files_struct  有描述符 就是inode,通常称为描述符了,

signal_struct 有描述符

image.png



多任务就是一个cpu上运行多个进程,所以进程切换不可避免,

如下图

进程切换即上下文切换(Context switch),

假设进程A切换成进程B,A的进程描述符被挂起,被Suspend,就要保存现场(保存在cpu内运行的stack pointer,other registers,EIP register, etc,,,,,,,保存在内存中的内核的进程描述符当中了) (进程描述符文件大小是固定的,),,,B进程resume,恢复现场了,把B的进程描述符文件读进来,(stack pointer读进CPU,other registers,EIP register读进寄存器)(EIP就是指令计数器吧)(每一个进程的other registers各不相同),EIP就指向下一条指令了,于是就装载并执行下一条指令,,,,,,这就是上下文切换


上下文切换是需要时间的,上下文切换由内核完成,不是进程自己完成,,,每一个进程切换由用户模式转到内核模式,再到用户模式,(假如用到系统调用,就又到内核模式...............),一直这样切换.,,,进程切换必须由内核来完成.

cpu时间有两部分:用户空间的所有时间加起来,内核空间的所有时间加起来

image.png


所有内核的时间(#top命令中的%sy)

%us 就是用户模式

%sy 就是系统模式,内核模式,,,,,,,内核模式不应该占据太多时间,因为工作是靠用户模式(比如web进程),如果大量时间在内核上,很可能是进程切换,中断次等过多导致的

如下图


image.png



 

上下文切换太频繁不好(内核占据过多时间),不频繁也不好(比如鼠标,键盘,要等好久,才会起作用)


linux: 支持进程抢占的

优先级高的进程可以抢占优先级低的进程,不是一上来随时可以抢的,而是有内部系统时钟,内部的时间嘀嗒,tick(嘀嗒),一秒中嘀嗒几次,就是时间解析度?????解析度越高,时钟频度越精准,,,内核内部有时间频率,100Hz(一秒钟嘀嗒100次,一个嘀嗒10毫秒),1000Hz(一秒钟嘀嗒1000次,一个嘀嗒1毫秒),操作系统根据嘀嗒的次数来决定时间走动的

时钟中断:每一次嘀嗒产生一个可抢的时钟中断


A:运行完要5ms, 时钟嘀嗒是1ms,,那么C在一次嘀嗒后抢过来后,,A剩下的4ms下次运行,,,若时钟嘀嗒是10ms,则A运行完了(只需要5ms),C才在一次嘀嗒后抢过来

C:


进程类别:

        交互式进程(I/O): I/O密集型,比如编辑器,大量的时间等在I/O上,对cpu量少,,

        批处理进程(CPU):CPU密集型,耗cpu大量的时间,比如守护进程,nginx服务器,,比如科学计算的进程,,比如处理mysql的查询

        实时进程(Real-time): 随时要运行,必须要立即得到响应的,优先级非常高的进程


PC桌面:交互式进程,通常应该高优先级

服务器: 它是CPU密集性的,不一定吧,有可能服务器也大量从硬盘读文件吧



一般调度器这样处理:CPU密集性的,时间片长,但优先级低;; I/O密集型时间片短,但优先级高


linux内优先级(priority)分为三类:

    实时优先级: 实时进程的优先级吗?????通常与内核相关的,或者非常关键性的任务相关的, 1-99,数字越小,优先级越低

    静态优先级: 通常用户空间的进程的优先级  100-139,数字越小,优先级越高

总范围: 1-139  (实际0-139),可以理解成1-139

    所有的实时优先级比静态优先级的优先程度更高


如下图 # top 命令


PR:priority优先级,,,,,,RT:real time,表示是实时优先级,(1-99之间的某一个值),20表示100之后的值,即120? 

NI:  nice值,

image.png



http://honglus.blogspot.com/2011/03/understanding-cpu-scheduling-priority.html

$  ps -e -o class,cmd | grep sshd  #查看优先级

$ ps -e -o class,rtprio,pri,nice,cmd #查看实时优先级

[root@localhost ~]# ps -e -o class,rtprio,pri,nice,cmd             # -e所有跟终端相关的和无关的查程

-o表示自定义显示的字段 class:调度类别 ,,,,,,,,,rtprio,(real time priority)实时优先级,,,,,,,,,,pri,优先级,静态优先级,,,,,,,,,,nice,调整静态优先级的

CLA: class 类别,调度类别  FF是FIFO   TS就是Others

RTPRIO: real time priority 实时优先级

NI: nice值,调整静态优先级的  -20,19 对应于静态优先级的100,139,,所以nice值为0,静态优先级就是120,,,默认启动每一个进程的nice值就是0(即静态优先级是120)

/sbin/init 是用户空间的进程,不是实时进程 (所谓的init进程,它是第一个由内核启动的用户级进程。)??????,NI值为0,所以优先级是120(这里怎么是19??)(因为进行了动态优先级的调整??????)

 [kthreadd]这里加上中括号,表示是一个内核线程?????,,,有些内核线程的优先级是实时的,比如[migration/0],[watchdog/0],它们是PRI是没有意义的,RTPRIO是99,意味着实时优先级里面最高的,意味着只要它想运行,就一定得运行,,,,其它的如[ksoftirqd/1]是正常的优先级,PRI是19,是以用户优先级的方式来定义的

内核在实现调度的时候,对两种不同优先级的进程进行调度的方法是不一样的


image.png


内核的调度类别

    三个调度器分别用来调度不同优先级的进程,不同类的进程

        实时进程:调度器有两个

                SCHED_FIFO:  scheduler  first in first out,调度先进先出,先运行完了,其它进程才能运行,调度方法很粗糙

                SCHED_RR:  scheduler  Round Bobin 调度是轮调的,每个进程有时间片,就算是实时的?????,优先级一样,时间片运行完了,就换同级别的下一个,

      SCHED_OTHER:  (linux中)scheduler  other 调度其它的,调度用户空间(100-139之间的)进程的,,,, 在unix (SCHED_NORMAL) 未必调度的都是用户空间的线程,用来调度100-139之间的优先级的进程,,按优先级进行调度


除了有些实时进程之外,大多数进程,包括内核线程都是用户空间运行(都以other来调度)


假设好多 100-139

    10个110 

    30个115

    50个120

    2个130

根据优先级,130的进程始终运行不上去,


内核中引入了动态优先级的概念

动态优先级

        主要是对100-139的进程,内核随时监控着这些进程,某一进程很长时间没有运行了,内核在自己的内部会临时性的调高它的优先级,,,,比如假设 把 130调成 105,立刻优先级变高, 由此它就运行了,临时调整,非永久调整,,,,,,,有时,因某进程过多频繁的运行,也会调低优先级,,,


dynamic priority = max (100, min (  static priority - bonus + 5, 139))

# static priority - bonus 就是静态优先级 - 奖惩措施    bonus的范围是 0-10之间

假如 110, 3

它的优先级为  max(100,min(110-3+5,139) 结果为112

假设因动态优先级的调整专门向外提供服务的进程的优先级太低,,,因为本来提供服务的进程的优先级太高,对提供服务的进程进行了惩罚,,,但是本来规划提供服务的进程的优先级应该高点,所以要手动调整优先级


手动调整优先级

        100-139: 调整nice值

            nice N  COMMAND: 表示以这个值来启动命令

            renice -n # PID: 已经启动的进程修改

            chrt  -p [prio] PID #也能调整100-139        #chrt  即 change real time

        1-99:

            chrt: ( change real time priority 改变实时优先级 )

                chrt -f -p [prio] PID        #fifo类别的

                chrt -r -p [prio] PID        #rr类别的

                chrt -f -p [prio] COMMAND        #启动命令时直接指定优先级       


ps -e -o class,rtprio,pri,nice,cmd    #查看实时优先级




[root@localhost ~]# man chrt

Cannot open the message catalog "man" for locale "zh_CN.UTF-8"

(NLSPATH="/usr/share/locale/%l/LC_MESSAGES/%N")


Formatting page, please wait...

CHRT(1)                       Linux User’s Manual                      CHRT(1)


NAME

       chrt - manipulate real-time attributes of a process


SYNOPSIS

       chrt [options] prio command [arg]...    #启动时直接指定优先级命令

       chrt [options] -p [prio] pid        #-p优先级 pid是进程id号


DESCRIPTION

       chrt(1)  sets  or  retrieves  the real-time scheduling attributes of an

       existing PID or runs COMMAND with the given  attributes.   Both  policy

       (one  of SCHED_OTHER, SCHED_FIFO, SCHED_RR, SCHED_BATCH, or SCHED_IDLE)

       and priority can be set and retrieved.


       The SCHED_BATCH policy is supported since Linux 2.6.16. The  SCHED_IDLE

       policy is supported since Linux 2.6.23.


OPTIONS

       -p, --pid

              operate on an existing PID and do not launch a new task


       -b, --batch        #调整批处理进程类别????

              set scheduling policy to SCHED_BATCH (Linux specific)


       -f, --fifo        #调整fifo类别

              set scheduling policy to SCHED_FIFO


       -i, --idle       #调整空闲进程类别????

              set schedulng policy to SCHED_IDLE (Linux specific)


       -m, --max

              show minimum and maximum valid priorities, then exit

      -o, --other      #调整other类别

              set policy scheduling policy to SCHED_OTHER


       -r, --rr       #调整rr类别

              set scheduling policy to SCHED_RR (the default)


       -h, --help

              display usage information and exit


       -v, --version

              output version information and exit



如下图,有数百个进程,

linux2.6以后的版本,将所有进程分为139*2的队列,优先级为1的排在1号队列上,

优先级为2的排在2号队列上,,,,,,优先级为99的是优先级最高的,扫描139(140)个队列的首部(就是每一个队列的第一个进程吧),从99到1,再从100到139,从每个队列里取一个??? 按从高到低排,,,这里把2号第一个拿出来运行,再2号第二个拿出来运行,再2号第三个拿出来运行,,,然后把1号第一个拿出来运行,,,最后把139号.........

image.png

如下图

假设139号第一个未运行完,只运行了一次10s,还需要5s才能运行完,,,,每个列队有两个,一个叫活动队列,一个叫过期队列,从活动队列运行完后(未运行完成)就放到过期队列里,,,下图就是把三个放到过期队列里,,,,当第二次运行的时候,就把活动队列和过期队列调换下,(省得复制和重新排队了)

image.png


如下图,,每一次扫描,139(140)个,,挑出优先级最高的那个,,,这就是O(1)算法,,,,,,,好像linux2.6.18之后的内核里,运行的是CFQ的队列( Complete Fair Queue 完全公平队列 有人称为CFS,Complete Fair Scheduler 完全公平调度器 ),主要是用来实现SCHED_OTHER的,,,,,,CFQ不太适合于服务器,适合于桌面系统,

image.png


如下图

进程的格式,一个进程的内部,在它的线性地址空间里面,从0x0000,到0xffff,有一段空间是不能使用的,线性地址空间是4G(32位系统上),但有1G是留给内核,,,,进程自己的空间当中,从低地址开始,放的是只读段(代码指令区 Text),,Data区(有了初始数据的变量),,BSS(初始化为0的变量),,堆(比如打开的文件内容,通常在堆上),,栈(本地变量,函数的参数,函数的返回值,返回地址????等等,,,, 程序执行过程中的变量所保存的值,随时可能被撤销),,,,,,栈是从高地址空间向低地址空间增长的,堆是从低地址空间向高地址空间增长的,

image.png


如下图

所谓的init进程,它是第一个由内核启动的用户级进程。

linux如何创建进程,COW机制( Copy On Write 在写的时候才复制 ),linux每一个进程由父进程生成,第一个进程是init,由Kernel生成的,,,其它所有进程由init(或其子进程)来生成,,,除了init进程,其它进程都有父进程,每一个进程由父进程fork()系统调用生成,,,,创建一个进程,最重要的是创建进程描述符task_struct(这是由内核来完成),,,,一个进程要有内存空间,pid(进程id),ppid(父进程id)

一个进程刚创建时,内存的地址指向与父进程是同一个位置, 

        memory-->parent

当父进程或子进程需要写的时候,它们才分家 

        COW:Copy On Write

这样才会大大降低进程的资源开销,因为很多子进程只是执行额外的操作,而不是写额外的数据,就退出了,,,所以很多子进程不需要创建额外的地址空间的,这大大降低了进程创建的开销,

但是创建进程反正是有开销的,apache的prefork模型,任何一个用户请求来了,要用进程响应,当请求批量退出以后,进程要销毁,再来一批,再创建,,,,,然后销毁,,,再创建,所以性能不高,

image.png


普通分类: