Windows线程调度策略超详细

Windows 采用基于优先级的、抢占调度算法来调度线程。

用于处理调度的 Windows 内核部分称为调度程序,Windows 调度程序确保具有最高优先级的线程总是在运行的。由于调度程序选择运行的线程会一直运行,直到被更高优先级的线程所抢占,或终止,或时间片已到,或调用阻塞系统调用(如 I/O)。如果在低优先级线程运行时,更高优先级的实时线程变成就绪,那么低优先级线程就被抢占。这种抢占使得实时线程在需要使用 CPU 时优先得到使用。

调度程序采用 32 级的优先级方案,以便确定线程执行顺序。优先级分为两大类:可变类包括优先级从 1〜15 的线程,实时类包括优先级从 16〜31 的线程(还有一个线程运行在优先级 0,它用于内存管理)。

调度程序为每个调度优先级采用一个队列;从高到低检查队列,直到它发现一个线程可以执行。如果没有找到就绪线程,那么调度程序会执行一个称为空闲线程的特别线程。

在 Windows 内核和 Windows API 的数字优先级之间有一个关系。Windows API 定义了一个进程可能属于的一些优先级类型。它们包括:
  • IDLE_PRIORITY_CLASS
  • BELOW_NORMAL_PRIORITY_CLASS
  • NORMAL_PRIORITY_CLASS
  • ABOVE NORMAL_PRIORITY_CLASS
  • HIGH_PRIORITY_CLASS
  • REALTIME_PRIORITY_CLASS

进程通常属于类 NORMAL_PRIORITY_CLASS。进程属于这个类,除非进程的父进程属于类 IDLE_PRIORITY_CLASS,或者在创建进程时指定了某个类。此外,通过 Windows API 的函数 SetPriorityClass(),进程的优先级的类可以修改。除了 REALTIME_PRIORITY_CLASS外,所有其他类的优先级都是可变的,这意味着属于这些类型的线程优先级能够改变。

具有给定优先级类的一个线程也有一个相对优先级。这个相对优先级的值包括:
  • IDLE
  • LOWEST
  • BELOW_NORMAL
  • NORMAL
  • ABOVE_NORMAL
  • HIGHEST
  • TIME_CRITICAL

每个线程的优先级基于它所属的优先级类型和它在该类型中的相对优先级,图 2 说明了这种关系。

Windows线程优先级
图 1 Windows 线程优先级

每个类型的值出现在顶行。左列包括相对优先级的值。例如,如果 1 个线程属于 ABOVE_NORMAL_PRIORITY_CLASS 型,且相对优先级为 NORMAL,那么该线程的优先级数值为 10。

另外,每个线程在所属类型中有一个优先级基值。默认地,优先级基值为一个类型的优先级相对值 NORMAL。每个优先级类型的优先级基值为:
  • REALTIME_PRIORITY_CLASS — 24
  • HIGH_PRIORITY_CLASS — 13
  • ABOVE_NORMAL_PRIORITY—CLASS — 10
  • NORMALJPRIORITY_CLASS — 8
  • BELOW_NORMAL_PRIORITY_CLASS — 6
  • IDLE_PRIORITY_CLASS — 4

线程的优先级初值通常为线程所属进程的优先级基值,但是通过 Windows API 的函数 SetThreadPriority() 也可修改线程的优先级基值。

当一个线程的时间片用完时,该线程被中断。如果线程属于可变的优先级类型,那么它的优先级就被降低。不过,该优先级不能低于优先级基值。降低优先级可以限制计算密集型线程的 CPU 消耗。

当一个可变优先级的线程从等待中释放时,调度程序会提升其优先级。提升数量取决于线程等待什么。例如,等待键盘 I/O 的线程将得到一个较大提升;而等待磁盘操作的线程将得到一个中等提升。采用这种策略,正在使用鼠标和窗口的线程往往得到很好的响应时间。这也使得 I/O 密集型线程保持 I/O 设备忙碌,同时允许计算密集型线程使用后台空闲的 CPU 周期。

此外,用户正在交互使用的窗口会得到优先级提升,以便改善响应时间。多个操作系统包括 UNIX,采用这种策略。

当用户运行一个交互程序时,系统需要提供特别好的表现。由于这个原因,对于类 NORMAL PRIORITY CLASS 的进程,Windows 有一个特殊调度规则。Windows 将这类进程分成两种:
  1. 前台进程,屏幕上已选的进程;
  2. 后台进程,屏幕上未选的进程;
当一个进程移到前台,Windows 增加它的时间片,通常是原来的 3 倍。这个增加给前台进程 3 倍的时间来运行(在被抢占前)。

Windows 7 引入用户模式调度(UMS),允许应用程序在内核外创建和管理线程。因此,一个应用程序在不涉及内核调度程序的情况下可以创建和调度多个线程。对于创建大量线程的应用程序,用户模式的线程调度比内核模式更加有效,因为不需要内核的干预。

早期版本的 Windows 提供了一个类似特征(称为纤程),允许多个用户模式线程(纤程)被映射到单个内核线程。然而,使用纤程实际上有限制。一个纤程不能调用 Windows API,因为所有纤程共享线程环境块(TEB)。这会产生一个问题,当 Windows API 函数将状态信息放到一个纤程 TEB 上,另一个纤程会改写这个信息。UMS 对这个问题的解决方法是,为每个用户模式线程提供它自己的上下文。

此外,与纤程不同的是,UMS 一般不是直接为程序员使用的。编写用户模式调度程序的具体细节可能很有挑战,而且 UMS 并不包括这种调度程序。不过,调度程序来自 UMS 之上的编程语言库。

例如,微软提供并发运行时库(ConcRT),这是一个 C++ 并发编程框架,用于在多核处理器上设计并行任务(更深入了解请猛击:《什么是多核》一文)。ConcRT 提供用户模式调度程序,并能将程序分解成任务,以便在可用处理核上进行调度。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


起步 处理器架构,参考 x86是指intel的开发的一种32位指令集 intel和amd早期的cpu都支持这种指令集 AMD比Intel率先制造出了商用的兼容x86的CPU,AMD称之为AMD64 Intel选择了设计一种不兼容x86的全新64为指令集,称之为IA-64,后来支持AMD64的指令集,
pscp pscp -P 22 C:\work\test.txt root@192.168.1.5:/home/data pscp -P 22 root@192.168.1.5:/home/data/test.txt C://work// 检索 find / -name default.config
文件处理 ls -a # 显示所有文件 ls -l # 显示详细信息 ls -d # 显示路径 mkdir /目录名称 # 创建目录 cd /目录名称 # 切换目录 pwd # 显示当前路径 rmdir /目录名称 # 删除目录 cp -rp [目录名称] [目标目录] # 复制目录到目标目录 cp
准备一台电脑(我就用联想拯救者r7000演示) 参考博客制作启动盘 插上U盘,启动电脑,一直按F2 进入如下页面后,将U盘设置为第一启动项,点击exit,保存并退出 之后进入如下页面,选择第三项 进入如下页面,选择第四项 进入如下页面,选择第一项,选中后,先不要点Enter 按e键,将inst.st
认识 Linux系统是参考了UNIX系统作为模板开发的,但没有使用UNIX的代码;是UNIX的一种,但不是衍生版 在Linux内核的基础上开发是发行版 分区 逻辑分区永远从5开始 步骤 挂载:可理解为分配盘符,挂载点即是盘符名;不同之处:Linux中是以空目录名称作为盘符 Hda 第一块硬盘 Hda
文件处理命令 以 . 开头的文件是隐藏文件 以 - 开头表示这是一个文件 以 d 开头表示是一个目录 以 l 开头表示是一个软链接 第一个root是所有者,第二个root是所属组 ls -h 以文件默认大小后缀 显示 ls -i 查看i节点(唯一标识) 所有者:只能有一个,可变更 所属组:只能有一个
参考 01 02 03 前提环境 本地安装VirtualBox,并安装CentOS8,配置网络后,window系统上putty能连接到CentOS8服务器 配置步骤 右键服务器复制 启动复制后的服务器,查看ip和hostname发现和原来的服务器一样,需要修改 hostname # 查看主机名 vi
文件搜索命令 星号匹配任意字符,问号匹配任意单个字符 -iname 根据文件名查找且不区分大小写 -ok 命名会有一个询问的步骤 如果没有找到指定文件,可输入命令:updatedb 更新文件资料库;除tmp目录不在文件资料库收录范围之内 locate -i 文件名 # 检索时不区分大小写 which
安装环境 安装最新版的Virtual Box,点击安装 下载centos8镜像 创建虚拟机,可参考 选择下载到本地的镜像 设置启动顺序 点击启动 启动过程中报错:“FATAL:No bootable medium found!” 1.没有选择iso镜像 2.光驱没有排在第一位置 3.镜像只能选择x8
Linux严格区分大小写 所有内容文件形式保存,包括硬件 Linux不靠扩展名区分文件类型 挂载:将设备文件名和挂载点(盘符)连接的过程 Linux各个目录的作用 bin表示二进制 服务器注意事项 远程服务器不允许关机,只能重启 重启时应该关闭服务 不要在服务器访问高峰运行高负载命令 远程配置防火墙
IDE连接Linux,上传下载文件 参考1 参考2 连接Linux 上传下载文件 本地项目打包后上传 查看是否上传成功,右键下载 补充 后端项目开发完成后,需clean掉临时文件target文件夹,且只推送修改过的文件 前端项目开发的过程中,需要在每个子组件中使用scoped,确保每个子组件中的编码
起步 LTS与普通版本的区别 LTS版本的发布周期更长,更加稳定 安装jdk sudo mkdir /usr/lib/jvm # 在Ubuntu中创建目录 pscp D:\安装包\linux源码包\jdk-8u291-linux-x64.tar.gz chnq@192.168.0.102:/tmp
前言 最近在b站上看了兄弟连老师的Linux教程,非常适合入门:https://www.bilibili.com/video/BV1mW411i7Qf 看完后就自己来试着玩下,正好手上有台空闲的电脑就尝试不使用虚拟机的方式安装Linux系统 安装步骤 制作启动盘 下载ISO镜像,我这里下载的是Cen
新建虚拟电脑 设置内存和处理器 设置硬盘大小 完成 设置 查看光驱 设置启动顺序 点击启动 选择第1项 进入图形安装界面 选择安装位置,开始安装 设置root密码 重启 登录 查看本地文件夹 配置网络,点击设置 查看宿主机ip C:\Users\ychen λ ipconfig 无线局域网适配器 W
源码包安装需手动下载后安装 二进制包则在package目录下 rpm命令管理rpm包 若某个rpm包依赖于某个模块,需要到网站www.rpmfind.net查询该模块依赖的包,安装这个包后自动安装模块,之后就能安装rpm包了 安装升级时使用包全名 查询卸载时使用包名 虚拟机中的Linux系统安装rp
首先进入命令模式,再输入以下命令 命令模式用于输入命令 插入模式可对文件编写操作 编辑模式下的命令是在冒号后输入 :12, 15d # 删除指定范围的行,这里是删除12到15行 :n1,n2s/old/new/g ## 表示从n1行到n2行,old表示旧的字符串 vim使用小技巧:自定义快捷键,如快
使用源码包安装,需要自己指定安装位置,通常是 /usr/local/软件名/ linux中要想启动执行文件,应使用绝对路径 /绝对路径/rpm包名 start ## 执行方式一 service rpm包名 start ## 执行方式二 使用源码包安装后,由于自定义安装路径,就不能使用service命
网络命令 在收邮件的用户中,输入 mail 可查看邮件信息,输入序列号查看详细信息 在mail命令下,输入h 查看所有邮件的列表 输入:d 序列号 # 删除邮件 last # 统计所有用户登录或重启时间,用于日志查询 lastlog # 显示包括未登录用户的登录时间 lastlog -u 用户id
若要使用yum管理,必须能连接网络,首先配置网络IP 进入yum源文件中启动容器 使用yum源头安装rpm包不需要进入package路径,同时也不需要使用包全名,会有yum自动管理 安装软件组
简介 client即是本机安装的docker,相当于git Docker_host相当于centos系统 registry则是docker仓库,相当于GitHub 镜像用于创建docker容器,一个镜像可以创建多个docker容器 容器是由镜像创建的运行实例,(镜像相当于类,容器相当于类创建的对象)