每个现场都有一个上下文。后者保存在线程的内核对象中。这上下文反应了线程上一次执行时CPU寄存器的状态,大约每隔20ms(GetSystemTimeAdjustment函数第二个参数的返回值),windows都会查看所有当前存在的线程内核对象,在这些对象中,只有一些被认为是可以调度的,windows在可调度的线程内核对象中选择一个,并将上次保存在线程上下文中的值载入CPU寄存器,这一操作被称为上下文切换。

在县城初始化之后,CreateProcess或者CreateThread函数将查看是否有CREATE_SUSPENDED标志传入,如果有,函数会返回并让新线程处于挂起状态。如果没有函数将线程的挂起计数递减为0,当线程的挂起计数为0时,线程就成为可调度的,除非还在等待某个事件 的发生。通过创建一个处于挂起状态的线程,我们可以通过ResumeThread来恢复线程。同样也有SuspendThread可以挂起线程。

线程可以告诉系统要休眠,调用Sleep函数

1.调用Sleep函数将使得线程资源放弃属于他的时间片中剩下的部分

2.系统设置线程不可调度的时间只是近似于所设定的毫秒数,windows不是实时操作系统,线程实际醒来的情况取决于系统中其他线程的运行情况

3.可以调用Sleep函数并给dwms参数传入INFINITE,这是在告诉系统,永远不要调度这进程

4.Sleep(0),这是在告诉系统,主调线程放弃了时间片的剩余部分,它强制系统调度其他线程,但是系统有可能重新调低刚刚调用了sleep(0)的线程,如果没有相同或者较高优先级的可调度线程时,就会发生这样的情况。

切换到另一个线程

系统提供了一个名为SwitchToThread的函数,如果存在另一个可调度的线程,那么系统会让此线程运行。

Bool SwitchToThread();

调用这函数时,系统查看是否存在正急需CPU时间的饥饿线程,如果没有,函数立即返回,如果存在,则调度该线程(其优先级可能比SwitchToThread的主调线程低),饥饿线程运行一个时间量,然后系统调度程序回复正常运行。

通过调用SwitcgToThread和调用Sleep(0)类似,区别在于SwitchToThread运行执行较低优先级的线程。

线程的执行时间

有时候我们需要计算一个线程执行某项任务需要消耗多长时间,关于这一点,可以利用GetTickCount64();

但是有一个前提就是代码的执行不会被中断,可是在抢占式的操作系统,这样是比较困难的。

BOOL WINAPI GetThreadTimes(_In_   HANDLE hThread,//需要获取cpu时间的线程句柄_Out_  LPFILETIME lpCreationTime,//创建时间_Out_  LPFILETIME lpExitTime,//退出时间_Out_  LPFILETIME lpKernelTime,//内核时间_Out_  LPFILETIME lpUserTime//用户时间
);

同样的也有GetProcessTimes,可以用于进程中的所有线程。

BOOL WINAPI GetProcessTimes(
__in HANDLE hProcess,
__out LPFILETIME lpCreationTime,
__out LPFILETIME lpExitTime,
__out LPFILETIME lpKernelTime,
__out LPFILETIME lpUserTime
);

hProcess:为需要获取相关时间的进程句柄
lpCreationTime:进程的创建时间
lpExitTime:进程的退出时间
lpKernelTime:进程在内核模式下的所有时间
lpUserTime:进程在用户模式下的所有时间

BOOL QueryPerformanceFrequency(LARGE_INTEGER *pliFrequency)
BOOL QueryPerformanceCounter(LARGE_INTEGER *pliCount);

这两个函数假设正在执行的线程不会被抢占。它们都是针对生命期很短的代码块。GetCPUFrequencyInMHZ可以获得cpu频率。

在windows定义的所有数据结构中,CONTEXT结构是唯一一个依赖于cpu的。我们可以通过调用GetThreadContext来获得当期cpu寄存器的状态。

BOOL GetThreadContext(HANDLE hThread, LPCONTEXT lpContext);

hThread:获取信息目标进程的线程句柄。(用OpenThread获取)
lpContext:一个用于接收信息的CONTEXT结构指针
返回值:如果成功,返回值不为零,如果不成功,返回值为零,若想看其他的错误信息,参考GetLastError

第二个参数是CONTEXT结构指针。在分配CONTEXT结构后,需要初始化ContextFlag标志,表示以表示要获取哪些寄存器。函数执行后CONTEXT对象中就填入我们请求的成员。

ContextFlag可以是:

CONTEXT_CONTROL表示控制寄存器。
CONTEXT_INTEGER表示整数寄存器。
CONTEXT_FLOAT 表示浮点寄存器。
CONTEXT_ALL 表示CONTEXT_CONTROL |CONTEXT_INTEGER|CONTEXT_SEGMENTS。

在调用GetThreadContext时,需要先调用SuspendThread。因为在调用GetThreadContext时系统可能正在执行那个线程,此时线程的上下文与获得的信息就不一致了。注意,它只能返回线程的用户模式上下文。如果当调用SuspendThread时线程正在内核模式运行,线程不会暂停,直到其返回用户空间。但是返回到用户控件后不会执行任何用户模式代码。

不仅仅能获得线程的进程上下文,我们还可以设置它。这可以调用:

BOOL SetThreadContext( HANDLE hThread,CONST CONTEXT *pContext);

GetThreadContext和SetThreadContext函数为我们提供了对线程许多控制的方法,但是需要小心使用。

线程优先级

前面提到的调度程序在调度另外一个线程之前,可以运行一个线程大约20ms的时间。但是这是所有优先级都相同的情况。实际上系统中的很多线程优先级是不同的,这将影响调度程序如何选择下一个要运行的线程。

Windows的线程优先级从0到31。每个线程都会分配一个优先级。当系统确定给哪个线程分配cpu时,它会首先查看优先级为31的线程,直至所有优先级为31的线程都被调度。然后再查看下一优先级线程。只要存在优先级为31的线程,系统就不会调度0-30级的线程。低优先级线程长时间得不到cpu时间,这被称为饥饿。这不经常出现,因为大多数线程都是不可调度的。

系统启动时会创建一个优先级为0的idle线程,整个系统只有它的优先级为0。它在系统中没有其他线程运行时将系统内存中所有闲置页面清0。

Windows中的线程优先级是由优先级类和相对线程优先级来确定的。系统通过线程的相对优先级加上线程所属进程的优先级来确定线程的优先级值。这个值被称为线程的基本优先级值。

Windows支持6个进程优先级类:idle ,below normal ,normal ,above normal,high和real-time。它们是相对与进程的。Normal最为常用,为99%的进程使用。

idle优先级类在系统什么都不做的时候运行的应用程序。如屏幕保护程序。real-time优先级类优先级别最高,但是没有开放给用户使用。因为此优先级类的程序会影响操作系统的任务。

Windows支持7个相对线程优先级:idle,lowest ,below normal,normal,above normal,highest和time-critical。这些优先级是相对于进程优先级的。大多数的线程使用normal优先级。

概括起来就是进程属于某个优先级类,另外还可以指定进程中线程的相对线程优先级。也就是说线程优先级是相对于进程优先级的。time-critical优先级对于real-time优先级类,优先级为31。相对于其他优先级类则为15。需要注意的是进程优先级是抽象的概念,因为进程并不参与调度。
在优先级编程时,首先需要在调用CreateProcess时可以再fdwCreate参数中传入想要的优先级。fdwCreate可以是以下标识符:
real-time        REALTIME_PRIORITY_CLASS
high            HIGH_PRIORITY_CLASS
above normal     ABOVE_NORMAL_PRIORITY_CLASS
normal          NORMAL_PRIORITY_CLASS
below_normal    BELOW_NORMAL_PRIORITY_CLASS
idle             IDLE_PRIORITY_CLASS

进程运行后可以调用SetPrioritClass来改变进程优先级类。

BOOL SetPriorityClass(HANDLE hProcess,DWORD fdwPriority);

可以调用GetPriorityClass来获得进程的优先级类。DWORD GetPriorityClass(HANDLE hProcess);
上面是指定的进程优先级类,调用CreateThread创建线程时,它的线程优先级总是被设置为normal.

关联性
    默认情况下,windows在分配cpu时采用软关联的方式。也就是说在其他因素相同的情况下,系统使线程在上一次运行的处理器上运行。这有助于重用仍在处理器高速缓存中的数据。
系统在启动时确定cpu数量。应用程序可以通过调用GetSysInfo来查询cpu的数量。如果需要限制一个进程的所有线程在某些cpu上运行,可以调用:

BOOL SetProcessAffinityMask( HANDLE hProcess,DWORD_PTR dwProcessAffinityMask);
第一个参数代表要设置的进程句柄。
第二参数是一个位掩码。代表线程可以在哪些cpu上运行。
注意子进程将继承父进程的关联性。
GetProcessAffinityMask返回进程的关联掩码。
相应的还可以设置某个线程只在一组cpu上运行:
SetThreadAffinityMask。
有时候强制一个线程只在某个特定的cpu上运行并不是什么好主意。Windows允许一个线程运行在一个cpu上,但如果需要,它将被移动到一个空闲的cpu上。
要给线程设置一个理想的cpu,可以调用:
DWORD SetThreadIdealProcessro(HANDLE hThread,DWORD dwIdealProcessor);
dwIdealProcessor是一个0到31/63之间的整数。表示线程希望设置的cpu。可以传入MAXIMUM_PROCESSOR值,表示没有理想的cpu。

线程调度优先级和关联性相关推荐

  1. Windows核心编程:第7章 线程调度、优先级和关联性

    Github https://github.com/gongluck/Windows-Core-Program.git //第7章 线程调度.优先级和关联性.cpp: 定义应用程序的入口点. //#i ...

  2. C# 运算符的优先级和关联性

    表1 显示了 C#运算符的优先级,其中顶部的运算符有最高的优先级(即在包 含多个运算符的表达式中,最先计算该运算符). 除了运算符优先级,对于二元运算符,需要注意运算符是从左向右还是从右向左计算.除了 ...

  3. Java 从多线程到并发编程(五)—— 线程调度 优先级倒置(反转) 阻塞 死锁 suspend

    文章目录 前言 ´・ᴗ・` 线程调度策略 优先级倒置问题 优先级倒置解决方案 死锁 dead lock suspend 被阻塞的同时持有资源不放 是上述问题的诱因 总结 ´◡` 前言 ´・ᴗ・` 这一 ...

  4. 【Linux 内核】线程调度示例一 ③ ( 获取线程优先级 | 设置线程调度策略 | 代码示例 )

    文章目录 一.获取线程优先级 1.pthread_attr_setschedparam 和 pthread_attr_getschedparam 函数 2.获取线程优先级代码示例 二.设置线程调度策略 ...

  5. linux设置进程优先级,Linux线程属性及优先级设置

    POSIX.1线程属性及优先级设置 By zieckey All Right Reserved 线程的属性由pthread_attr_t结构类型表示. 在使用pthread_attr_t之前,需要调用 ...

  6. Linux线程属性及优先级设置

    Linux线程属性及优先级设置 [原文引自]http://hikesoso2010.spaces.eepw.com.cn/articles/article/item/86413# 线程的属性由pthr ...

  7. What is Java thread priority? 什么是java线程优先级

    就一个小程序,运行一次输出结果不一样,这是因为线程调度方法不能确定,取决你当前操作系统的进程,线程调度优先级. 所以要想线程按一定的顺序运行,哪么只能选择Synchronized 互斥(对象锁)和 w ...

  8. Linux线程调度bug,Linux线程调度引起的业务问题

    一. 问题现象 1.业务组播出向报文偶尔有延迟: 2.单播出向报文平滑 二. 分析及定位 使用wireshark分析了组播出向报文的抓包,报文无丢包,但是IO 输出流量显示有burst和掉坑现象. 波 ...

  9. Window核心编程

    Window核心编程 第一章:错误处理 FormatMessage/LocalLock\LocalFree 第二章: TEXT("..") TCHAR(CHAR,WCHAR)  安 ...

最新文章

  1. 死锁产生的原因和解锁的方法
  2. c语言 真假条件跳转语句,什么是无条件跳转语句(C++)
  3. 机器学习工程师需要具备的5种软技能
  4. Android Studio 使用入门及问题汇总
  5. 使用Nomad构建弹性基础架构: 作业生命周期
  6. .NET Framework 各版本区别
  7. 《C语言编程魔法书:基于C11标准》——第一篇 预备知识篇 第1章 C魔法概览1.1 例说编程语言...
  8. 网络连接异常、网站服务器失去响应_网站常见故障解决办法
  9. 一行代码,揭开 CPU 执行原理!
  10. Linux下.o,.so,.a,.la文件
  11. TensorFlow2.0:数据统计
  12. android电容触摸屏的驱动及其上层工作原理,电容触摸屏驱动原理
  13. (minio学习过程2)纠错码
  14. 远程桌面链接怎么共享本地磁盘
  15. python栈是什么意思_Python算法之栈(stack)的实现
  16. 图标(Icon)和图标按钮(IconButton)
  17. Python实用功能之pdf文件转png图片数据
  18. NumPy 数组的维度变换
  19. 基于MATLAB的人脸考勤识别系统
  20. there can be only one auto column and it must be defined as a key原因以及解决办法

热门文章

  1. 大数据之Elasticsearch教程
  2. java 变量序列化_Java序列化与静态变量
  3. 详解Python的内置函数eval()
  4. 机器学习算法 随机森林学习 之决策树
  5. 使用ComplexHeatmap绘制3D热图
  6. 真正的出路只有一个(哈佛大学的幸福课)
  7. ubuntu下安装latex
  8. 如何在 Mac 上的“快速查看”中查看和编辑文件
  9. 1.9编程基础之顺序查找 05 最大值和最小值的差
  10. layui自定义ajax左侧三级菜单