1、windows是抢占式多线程操作系统
系统可以在任何时刻停止一个线程而另行调度另一个线程。
我们无法保证线程总在运行,线程会获得整个处理器,系统将不允许运行其他线程。
系统只调度可调度的线程,事实上,系统大多数线程都不是可调度的。有些线程对象的挂起计数大于0,这意味着该线程已经被挂起,不应该给它调度任何CPU时间。
除了被挂起的线程外,还有其他很多线程无法调度,因为它们都在等待某种事件发生。
2、线程的挂起和恢复
在线程内核对象中有一个值表示线程的挂起计数。
一个线程可以被挂起多次。如果一个线程被挂起三次,则在它有资格让系统为它分配CPU之前必须恢复三次。
任何线程都可以调用SuspendThread函数来挂起另外一个线程(只要获得线程的句柄)。显然,线程可以将自己挂起,但是它无法自己恢复。
实际开发中,应用程序在调用SuspendThread时必须小心,因为试图挂起一个线程时,我们不知道线程在做什么。只有在确切知道目标线程是哪个(或者它在做什么),而且采取完备措施避免出现挂起线程而引起的问题或者死锁的时候,调用SuspendThread才是安全的。
3、进程的挂起和恢复
windows不存在挂起和恢复进程的概念,因为系统从来不会给进程调度CPU时间。但是可以挂起一个进程中的所有线程。
4、睡眠
Sleep函数,线程可以告诉系统,在一段时间内自己不需要调度了。
(1) 调用Sleep函数,将使线程自愿放弃属于它的时间片中剩下的部分。
(2) 系统设置线程不可调度的时间只是“近视”所设定的毫秒数。因为windows不是实时操作系统。
(3) 可以调用Sleep函数传入INFINITE。这是在告诉系统,永远不要调度。这样做没有用处。
(4) 可以给Sleep传入0.这是在告诉系统,主调进程放弃了时间片的剩余部分。但是下一次时间片来的时候,线程可以被调度。
5、切换到另一个线程
SwitchToThread函数,如果存在另一个可调度线程,那么系统会让此线程运行。调用这个函数,系统查看是否存在正急需CPU时间的饥饿线程(其优先级可能比主调线程低)。如果有则调度该线程。饥饿线程可以运行一个时间量,然后系统调度程序恢复正常运行。
6、线程优先级
每个线程被赋予0~31的优先级数。系统调度程序总是先处理高优先级的线程。即较高优先级的线程总是会抢占低优先级的线程,无论较低优先级的线程是否正在运行。例如:如果有一个优先级为5的线程在运行,而系统确定有较高优先级的线程已经准备好了可以运行,它会立即暂停较低优先级的线程(即使后者的时间片还没有用完),并将CPU分配给较高优先级的线程,该线程获得一个完整的时间片。
当所有线程优先级都相同的情况下,在调度程序给另一个可调度线程分配CPU之前,CPU可以运行一个线程大约20ms。
windows支持6个进程优先级类(进程是不可调度的,进程优先级是Microsoft提出的一个抽象概念,有助于用户理解,所有的线程优先级是相对于进程优先级的),normal是最常用的优先级类,为99%的应用程序所使用。
windows支持7个相对线程优先级,这些优先级是相对进程优先级的,同样,大多数线程使用normal线程优先级。
线程优先级值没有为0的。这是因为0优先级保留给页面清零线程了。而且应用程序也不能获得一些优先级(这些优先级是留给内核模式下的设备驱动程序使用的)。用户所能知道的只能是线程的相对优先级。
7、动态提升线程优先级
系统通过线程的相对优先级加上线程所属进程的优先级来确定线程的优先级值。有时候,这也被称为线程的基本优先级值。偶尔,系统会提升一个线程的优先级——通常为了响应某种I/O事件比如窗口消息或者磁盘读取。另外一种提升优先级的情况是:当系统检测到有线程已经处于饥饿状态3到4秒时,它会动态将饥饿线程的优先级提升为15,并允许该线程运行两个时间片。当两个时间片结束后,线程的优先级立即回复到基本优先级。
8、关联性
默认情况下,windows vista 在给线程分配处理器时,使用软关联。意思是如果其他因素一样,系统将使线程在上一次运行的处理器上运行。让线程始终在同一个处理器上运行有助于重用仍在处理器高速缓存中的数据。
同时,windows vista 允许我们设置进程和线程的关联性,也就是说我们可以控制CPU让哪些CPU 运行特定的线程,这称为硬关联。