C#线程篇---Windows调度线程准则(3)
Windows本身就是一个抢占式操作系统,它的实现,必定有某种算法在里面,比如什么时候调度哪些线程,需要花费多长时间等问题。
我们时时在用Windows,作为程序员,我们有必要知道其中最贴近我们的算法。
为什么这么说?我们对系统发出的命令,获取信息等操作,Windows为什么能这么快作出反应吗?这仅仅是上下文切换那30毫秒的功劳吗?操作系统能依照人的操作,处理当前用户最迫切的请求,并在最短时间内给出反应,这些原因我们应该知道。
有人会提,这是线程的功劳,对。这是线程的功劳,你在操作的时候,都是线程在处理你的请求,现在来了解下线程的属性吧?
打开开始菜单,win7直接在搜索框中输入spy,然后会弹出一个叫spy++的程序,运行spy++。这个东西是VS2010完整版才有。
这是个有趣的东西,好奇的同学可以试试看。现在来看看这个东西能做什么吧。

我找到了一个QQ的线程的窗口,然后右键,弹出菜单,然后选择->消息。
出来一个框,数据一直再刷,然后再呼出QQ界面看?鼠标在QQ上面晃两下,细心的你会发现。刷屏的消息是不是很有感觉?再心细的又会观察一下属性选项,进程ID你也会看到,一个应用程序也就一个进程,关系QQ的线程,所有的进程ID都会是一样。在你每次操作的时候,Windows做着超乎你想象的工作,试一试,也许也会让你惊呼。消息看完了,来监视下线程吧?在spy++中选择 监视->线程
我找到的是QQ的线程:

上下文开关就是记录Windows上下文切换次数,”2453261“这是系统已经调用QQ线程的次数。而你看到的,就是一个线程的属性。
现在你也许又会有疑问了,为什么会这样?
在前两篇同系列文章中,提到过每个线程都有自己的属性,在每个线程的内核对象之中,都包含一个上下文结构,上下文结构的存在是为了反映在线程上一次执行时,线程CUP寄存器的状态。在任何时刻,Windows只将一个线程代码分配给一个CPU,一个线程只允许运行一个时间片,在线程的“时间片”结束之后,Windows会检查现有所有线程内核对象,只有那些没有在等待什么的线程才时候调度。Windows选择一个可调度的线程内核对象,并且换到它。
Windows选择一个可调度的线程有一套独特的标准,看到上图中的线程的优先级了吗?当前优先级和基本优先级,它是随着程序的启用与否波动的。
一个线程允许运行一个时间片,没错。但是,Windows执行线程的规律和时间片没多大的关系,线程在运行的任何时刻都可以停止,然后Windows又去调度另一个线程,你有点控制权,去控制你想运行的线程,但是这控制权不多,不控制为好。
对于线程的执行,记住一点:
你不能保证自己的线程一直运行,你不能阻止其他的线程的运行。
因为Windows不是一个实时操作系统,想了解更多就请自行去深挖吧,我也不多写了,免得扯出范围(─.─|||。
现在把目光放到线程优先级上,每个想成为优秀的程序员,必须要了解的知识点。
线程优先级别0~31,Windows把线程用从高到低的调度方式轮流调度线程,假如有一个优先级别为31的线程运行结束了,然后Windows会找下一个空闲的线程,如果空闲的线程中有一个级别也是31的线程,那么Windows又会把31级别的线程交给CUP处理。
那就有人要问了,如果一直有31的线程级别,那岂不是低级别的线程Windows都不会去调用了?这不公平。
确实,Windows就是个这样的不公平。有高级别线程,低级别线程没有机会去请求使用CUP。
CPU正在运行一个低级别的线程,当一个优先级别高于正在运行的低级别的线程,级别高的线程请求调用CPU,那么,会怎么样?
Windows会毫不犹豫的把正在运行的低级别线程赶走,然后放高级别的线程去使用CPU,就是有这么霸道。
较高优先级线程总是抢占较低级别线程,这有没有弱肉强食的感觉?
好,说完级别调用的问题,就来看看,怎么设计应用程序的运行线程级别吧。
在设计应用程序时,应觉得自己的应用程序是需要比机器上同时运行的其他应用程序更大还是更小的响应能力,然后选择一个进程优先级类(注意)。
为什么要引进进程优先级类?
Microsoft其实已经认识到,开发人员在为进程优先级分配时,很难做到完全合理,你不知道这个进程的优先级应该设为多少,为了解决这个分配优先级问题,Windows公开了优先级类的一个抽象层。以此来反应你的决定,Windows支持6个进程优先级类:Idel,Below Normal,Normal,Above Normal,Hight和Realtime(依次向高),其中Normal是默认的进程优先级,所以它是最常用的。
如果一个应用程序在系统什么都不做的情况下运行,就适合分配一个Idel的优先级类。估计QQ的离开状态,屏保等是这么设计的,当然还有很多....
进程划级时,要考虑最关键的因素,不能让进程妨碍其它更关键的任务,只有在绝对必要的时候才使用Hight优先级类,Realtime最高优先级一般得避免,因为它相当高,到31的级别了,它甚至可能干扰操作系统任务,比如阻碍一些网络传输,磁盘读写等,你肯能觉得没什么,除此之外,Realtime进程的线程可能造成不能及时的处理键盘和鼠标输入,用户觉得自己的计算机”崩了(死机)“,一定要有很好的理由才能使用Realtime优先级,比如响应一些延迟很短的硬件事件。
选好一个进程优先级类之后,你的程序和其他应用程序就不用再考虑了,现在把专注力放在应用程序的线程上:
Windows支持7个相对线程优先级:Idel,Lowest,Below Normal,Normal,Above Normal,Highest和Time-Critical。
这些是相对于进程优先级的,Normal依旧是默认的,它是最常用的,现在来打个比方,用个商场来做例子:

这图勉强入眼。
每个服饰品牌都不一样,代表着进程优先级不一样。
每个品牌下的服饰的价格不一样,代表着它们线程优先级不一样。
比如阿迪达斯,耐克等,它们进程优先级高,里面相对应的线程优先级也高。因为它们价格比一般的品牌要贵。
品牌的高低决定服装的价格,进程优先级的高低觉得相对线程优先级程度!经过这一举例,下面这个表应该看得懂了:
| 相对线程优先级 | 进程优先级 | |||||
|---|---|---|---|---|---|---|
| Idle | Below Normal | Normal | Above Normal | High | Realtime | |
| Time-critical | 15 | 15 | 15 | 15 | 15 | 31 |
| Highest | 6 | 8 | 10 | 12 | 15 | 26 |
| Above Normal | 5 | 7 | 9 | 11 | 14 | 25 |
| Normal | 4 | 6 | 8 | 10 | 13 | 24 |
| Below Normal | 3 | 5 | 7 | 9 | 12 | 23 |
| Lowest | 2 | 4 | 6 | 8 | 11 | 22 |
| Idle | 1 | 1 | 1 | 1 | 1 | 16 |
记住:
如果更改一个进程的优先级类,线程的相对优先级不会改变,但它的优先值会改变。
也许大家对这些表中数字会有疑惑,这代表的是先前说的0~31线程优先级别,但为什么这个表里面没有“0”这个级别?
“0”这个级别是有的,不过它保留给零页线程了,什么是零页线程?系统在启动时,会创建一个名为零页线程的特殊线程,它是整个系统唯一线程级别为0的线程,它辅负责在没有其他进程需要执行的时候,将系统的RAM所有空闲页清零。表中还有一些数字没有出现:17,18,19,20,21,27,28,29,30。这些线程级别不能被用户模式获得,在编写运行于内核模式的设备驱动程序时,才可以获得这些优先级。
还要注意的是,Realtime优先级的线程,其优先级不能低于16,类似的,非Realtime优先级的线程不能高于15。
进程优先级类和相对线程优先级有没有分清楚呢?这个概念容易引起混淆,大家可能认为Windows能调度进程,然而,Windows永远都不会调度进程,他调度的只有线程,“进程优先级类”是Microsoft提出的一个抽象概念,目的是为了帮助你理解自己的应用程序和其他正在运行的应用程序的关系,他没有别的用途。
来看个设计实例:
现在有一个线程要设计,他用于长时间运行的计算限制任务,比如:编译代码,拼音检查,电子表格计算等计算功能。一般是降低这线程的优先级,而不是提升线程的优先级。如果要设计一个快速的响应时间,然后运行非常短暂的时间,再回复等待状态,则应提高该线程的优先级,这里总结的规律是,高优先级线程在其生命中的大多数时间里,都应处于等待状态,这样才不会影响熊的总体响应能力。
现在请按一下键盘右下角位置的Windows菜单键,看到效果了?Windows菜单立即抢占其他低级线程,并显示它的菜单,用户在菜单中上下移动时,菜单的线程会快速响应每一次按键或者鼠标移动。这是个很好的高优先级线程的例子,它在用户关闭菜单后停止运行。
你可以更改它的线程相对优先级,Thread中的Priority属性,向它传递ThreadPriority枚举类型中定义的5各值之一,即在上表中的灰色部分列。
Windows为自己保留了优先级0和Realtime范围,CLR为自己保留了Idle 和Time-Critical优先级。
CLR的终结器线程以Time-Critical优先级运行。开发人员不用用到这些优先级,但了解一下还是不错的。
优先级的存在,使得应用程序需可以更人性化的处理用户的请求,这设计的相当不错,没有它,我们不能随意操控命令机器。
线程基础只是讲完了,作为开发人员应该知道,线程是非常宝贵的资源,必须省着用,为了做到这一点,最好的方式就是使用线程池ThreadPool。
这个下篇讲,不得不说,线程池自动管理线程的创建和销毁,这非常不错。(^。^)y-~~
C#线程篇---Windows调度线程准则(3)的更多相关文章
- java的守护线程与非守护线程
最近重新研究Java基础知识,发现以前太多知识知识略略带过了,比较说Java的线程机制,在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) ,(PS:以 ...
- [Java基础] java的守护线程与非守护线程
最近重新研究Java基础知识,发现以前太多知识知识略略带过了,比较说Java的线程机制,在Java中有两类线程:User Thread(用户线程).Daemon Thread(守护线程) ,(PS:以 ...
- JAVA技术专题综述之线程篇(1)
本文详细介绍JAVA技术专题综述之线程篇 编写具有多线程能力的程序经常会用到的方法有: run(),start(),wait(),notify(),notifyAll(),sleep(),yield( ...
- Python3 与 C# 并发编程之~ 线程篇
2.线程篇¶ 在线预览:https://github.lesschina.com/python/base/concurrency/3.并发编程-线程篇.html 示例代码:https://gith ...
- C#线程篇---你所不知道的线程池(4)
线程的创建和销毁都要耗费大量的时间,有什么更好的办法?用线程池! 太多的线程浪费内存资源,有什么更好的办法?用线程池! 太多线程有损性能,有什么更好的办法?用线程池!(⊙_⊙)? 线程池是什么?继前三 ...
- C#线程篇---解答线程之惑(2)
我们都知道,在这个行业,追求的就是用最少的时间学最多的知识,这是我写这个系列最想达到的目标,在最快的时间内,帮助更多的人学习更多的线程知识. 前一篇,讲述了线程基础,给大家铺垫了一个基础,这一篇着重介 ...
- Java内存模型与线程(二)线程的实现和线程的调度
先行先发生原则(happen-before原则) 先行先发生是指Java内存模型中定义的两项操作之间的偏序关系. 如果说A先行于B,其实就是说在发生B操作之前,操作A产生的影响能被操作B观察到,至于这 ...
- iOS开发:(线程篇-上)线程和进程
iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcod ...
- Java多线程系列--“基础篇”07之 线程休眠
概要 本章,会对Thread中sleep()方法进行介绍.涉及到的内容包括:1. sleep()介绍2. sleep()示例3. sleep() 与 wait()的比较 转载请注明出处:http:// ...
随机推荐
- python3使用csv包,读写csv文件
python操作csv,现在很多都用pandas包了,不过python还是有一个原始的包可以直接操作csv,或者excel的,下面举个例子说明csv读写csv文件的方法: import os impo ...
- python正则表达式,以及应用[下载图片]
regular expresion由一系列特定字符及其组合成的字符串,用来对目标字符串进行过滤操作.. re相关知识点 python正则表达式库为re,用import re导入,在然后用re.comp ...
- Python之并发编程-IO模型
目录 一.IO模型介绍二.阻塞IO(blocking IO)三.非阻塞IO(non-blocking IO)四.多路复用IO(IO multiplexing)五.异步IO(Asynchronous I ...
- 苏宁笔试:UML类图中的关系
1. 依赖 2. 关联 3. 聚合 4. 组合 5. 泛化 6. 实现
- String 类 的 使用
package com.StringUse; import java.util.Arrays; /* String 的构造方法: String() 创建一个空内容 的字符串对象. String(byt ...
- java 面试 -- 4
Java面试知识点总结 本篇文章会对面试中常遇到的Java技术点进行全面深入的总结,帮助我们在面试中更加得心应手,不参加面试的同学也能够借此机会梳理一下自己的知识体系,进行查漏补缺(阅读本文需要有 ...
- 我的寒假C(C++)学习计划
前言 要补缺加强C语言的想法由来已久,上学期因为种种原因,某些知识点学习得不是很理想,而且,许多地方也有加强的必要,所以这次布置的随笔可谓是来得恰到好处. 学习材料 C Primer Plus 师爷的 ...
- Sprint Boot入门(1):创建第一个Spring Boot应用
搭建工程 注:建议使用eclipse的STS插件创建Spring项目,而不是下面的Gradle项目,否则会导致有一些Spring文件不存在. new Gradle Project,如下 点next,如 ...
- 个人作业 - Week2 - 代码复审
代码复审Check List 概要部分 代码能符合需求和规格说明么? 能完成1~1000000个数独的求解与生成,并能处理异常输入,满足需求. 代码设计是否有周全的考虑? 为输入单独开设了一个输入检测 ...
- 多校联赛7 1001 hdu 4666(最远哈曼顿距离+优先队列)
吐个糟,尼玛今天被虐成狗了,一题都没搞出来,这题搞了N久居然还是搞不出来,一直TLE,最后还是参考别人代码才领悟的,思路就这么简单, 就是不会转弯,看着模板却不会改,艹,真怀疑自己是不是个笨蛋题意:求 ...