Intel x86的处理器状态有四个特权级别:0级权限最高,3级权限最低
导致处理器从用户态向内核态转换的时机
三类情况都通过中断机制发生
用户栈
核心栈
现代操作系统是由“中断驱动”的
中断是指程序执行过程中,遇到急需处理的事件时,暂时中止CPU上现行程序的运行,转去执行相应的事件处理程序,待处理完成后再返回原程序被中断处或调度其他程序执行的过程
在中断事件发生后,中断装置能改变处理器内操作的执行顺序
外中断(中断或异步中断):指来自处理器之外的中断信号
内中断(异常或同步中断):指来自处理器内部,通常由于程序执行中,发现与当前指令关联的、不正常的、或是错误的事件,内中断不可屏蔽
中断VS异常:
“中断”要求被快速处理,以便及时响应其它中断信号,所以,中断处理程序处理过程中是不能阻塞的;
“异常”处于被打断的当前进程上下文中,所提供的服务是当前进程所需要的,所以,异常处理程序处理过程中是可以阻塞的
中断允许发生嵌套,但异常大多为一重;
异常处理过程中可能会产生中断,但中断处理过程中决不会被异常打断
硬件故障中断
程序性中断
I/O中断
访管中断
时钟中断
Linux系统运行不同的间隔定时器,类型有三种
Linux系统允许进程同时启动多个定时器,定时器工作所需时间值及有关信息保存在进程的task-struct中
CPU可以通过指令设置可编程中断控制器的屏蔽码
中断屏蔽是指禁止CPU响应中断或禁止中断产生
负责对硬件做出迅速响应,并完成时间要求很严格的操作
上半部:中断处理程序
下半部:
没有严格的划分规则
软中断
tasklet
工作队列
tasklet实现在软中断之上;tasklet和软中断也称为可延迟函数
一组静态定义的下半部接口
软中断预留给系统中对时间要求最严格以及最重要的下半部使用
适用于执行频率很高且连续性要求很高的情况
基于软中断实现、灵活性强、动态创建
tasklet与软中断的权衡
tasklet调度:激活相应软中断的挂起状态
基于软中断实现、灵活性强、动态创建
将工作推后,交由一个内核线程去执行
工作队列vs.软中断/tasklet
“可再用” 程序
“可再入”
定义:
进程性质
分析
引入进程的代价:进程占用的空间、调度进程的时间代价
属性:
挂起状态引入原因
进程挂起的原因多种多样,如
进程不能立即被执行
进程映象定义
进程映象组成
进程上下文:
进程上下文组成:
也称为进程描述符(process descriptor)
进程控制块包含三类信息
进程队列:处于同一状态的所有PCB链接在一起的数据结构
队列排队规则
通用队列组织方式
进程上下文切换:
处理器的状态切换(用户态-内核态)不一定引起进程上下文切换
由操作系统中的原语实现:
当一个进程创建另一个进程时,生成进程称为父进程,被生成进程称为子进程,父进程可以创建多个子进程,从而形成树状族系关系
进程创建过程:
fork( ):父子进程是独立的进程
clone( ) :父子进程允许共享资源
vfork( ):子进程租用父进程地址空间
进程完成特定工作或出现严重错误后,必须被撤销,进程撤销可分为:正常撤销和非正常撤销
进程撤销过程:
进程阻塞步骤:
进程唤醒步骤:
解决思路:把进程的两项功能:“独立分配资源”与“被调度分派执行”分离开来
进程是操作系统中除处理器外进行的资源分配和保护的基本单位
线程是操作系统进程中能够独立执行的实体(控制流),是处理器调度和分派的基本单位
进程vs.线程
线程状态:运行、就绪、等待和终止
由于线程不是资源拥有单位,挂起状态对线程是没有意义
调度员/工作者模式
进程中的一个线程担任调度员,接收和处理工作请求,其他线程是工作者线程,由调度员线程分配任务并唤醒工作者线程
组模式
各个线程都可以取得并处理工作请求,有时每个线程被设计成专门执行特定任务,并建立相应任务队列
流水线模式
线程排成某个次序,第一个线程所产生的数据传送给下一个线程进行处理,依次类推,数据按照排定次序由线程依次传递以完成被请求的任务
多线程技术的应用
内核级线程KLT(如OS/2)
内核级线程指线程管理工作由内核完成,并提供线程API来使用线程
用户级线程ULT(如Java ,Informix)
用户级线程指线程的管理工作由应用程序来做,在用户空间内实现,内核不知道线程的存在
线程库是一个ULT管理的例行程序包,主要功能有:线程创建、调度、管理等
混合式线程(如Solaris)
实现分为两个层次:用户层和核心层
用户层线程在用户线程库中实现,核心层线程在内核中实现
在混合式线程系统中,内核必须支持内核级多线程的建立、调度和管理,同时也允许应用程序建立、调度和管理用户级线程
优点
缺点
优点
缺点
操作系统调度程序需要根据是用户级线程还是内核级线程来决定对进程和线程的调度方法
现代UNIX内核:引入三种机制优化进程创建效率
参考另一位博主的阐述:
- fork()函数调用之后子进程从fork()语句之后开始执行,其原因是子进程复制了程序计数器
- 在刚刚fork之后父子进程之间的数据段(全局变量),栈段(局部变量),堆段(动态内存),代码段,程序计数器等都是相同的(在当前的linux版本中遵从的是读时共享写时复制的原则)
- 父子之间不同的是进程ID,fork函数的返回值
- 共享的是文件描述符以及mmap建立的映射区 ———————————————— 版权声明:本文为CSDN博主「JoshuaCL」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_27357649/article/details/90939370
vfork()创建的子进程与父进程共享地址空间
与fork()的关系
参考另一位博主关于fork()与vfork()的详细解释:
可以看出使用vfork时,系统调用会等待子进程开始执行后返回,其实这样操作的原因也是因为子进程没有自己的页表项,如果不做等待的操作,会导致主进程和子进程使用同样页表,两个进程用样的页表,想想后果吧。
所以可以看出vfork和fork本质上的区别是:fork的子进程会拷贝主进程的页表项,而vfork的子进程共享主进程的页表项。因为这样的区别,所以使用vfork时主进程会等待子进程执行exec或exit操作后才会开始执行;如果vfork的子进程中不包含exec或者exit操作,而是直接退出,则会有导致主进程的操作异常,因为主进程的页表项在子进程退出的时候已经销毁,相当于主进程自己没了页表项。 那么vfork的好处是什么呢?避免一次主进程页表项的拷贝,因为子进程一般都会调用exec执行自己的程序代码,而在exec过程中会创建自己的页表项,根本不需要复制主进程的页表项。 那么vfork在现代Linux中是否真能体现它的优点呢?其实不尽然。 在拷贝页表项时,调用了函数dup_mm,其中会使用到COW(写时复制)技术(dup_mm-->copy_page_range),所谓的内存拷贝其实只是对内存的一个标记,只有在需要对该区域进行标记而已,并不会真正的拷贝。
———————————————— 版权声明:本文为CSDN博主「江明大吴」的原创文章,遵循CC 4.0
BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wu330/article/details/49127835
另一篇博主关于fork、vfork、clone的介绍blog
也称为守护进程,独立运行在内核空间的标准进程,支持内核在后台执行一些操作
与普通进程的区别:
mm
active_mm:主要用于优化
根据内存资源情况决定内存中所能容纳的进程数目,并完成外存和内存中的进程对换工作
根据某种原则决定就绪队列中的哪个进程/线程获得处理器,并将处理器出让给它使用
剥夺式(preemptive) ,又称抢先式
非剥夺式(nonpreemptive),又称非抢先式
剥夺式vs.非剥夺式
把SJF算法改为抢占式的:
FCFS与SJF是片面的调度算法
HRRF是介乎这两者之间的折衷的非剥夺式算法
静态优先数法
动态优先数法
时间片调度
轮转策略可防止那些很少使用外围设备的进程过长的占用处理器而使得要使用外围设备的那些进程没有机会去启动外围设备
轮转策略与间隔时钟 :时间片的设定
又称反馈循环队列或多队列策略
调度方法
调度策略
Linux 2.6负载均衡的“拉”操作基本思想