Windows高级编程之线程调度、优先级和亲缘性
2009-10-07 21:27
459 查看
7.1 暂停和恢复线程的运行
在线程内核对象的内部有一个值,用于指明线程的暂停计数。
线程恢复运行
DWORD ResumeThread(HANDLE hThread);
ResumeThread函数运行成功,它将返回线程的前一个暂停计数,否则返回0xFFFFFFFF。
线程暂停运行
DWORD SuspendThread(HANDLE hThread);
任何线程都可以调用该函数来暂停另一个线程的运行(只要拥有线程的句柄) 。线程可以自行暂停运行,但是不能自行恢复运行。
线程暂停的最多次数可以是MAXINUM_SUSPEND_COUNT次(在Wi n N T. h中定义为1 2 7)
7.2 暂停和恢复进程的运行
对于Wi n d o w s来说,不存在暂停或恢复进程的概念,因为进程从来不会被安排获得 C P U时间。
Wi n d o w s确实允许一个进程暂停另一个进程中的所有线程的运行,但是从事暂停操作的进程必须是个调试程序。特别是,进程必须调用WaitForDebugEvent和ContinueDebugEvent之类的函数。
Wi n d o w s没有提供其他方法来暂停进程中所有线程的运行。
7.3 线程睡眠
VOID Sleep(DWORD dwMilliseconds);
该函数可使线程暂停自己的运行,直到dwMilliseconds过去为止。注意:
• 调用Sleep,可使线程自愿放弃它剩余的时间片。
• 系统将在大约的指定毫秒数内使线程不可调度
• 可以调用Sleep,并且为dwMilliseconds参数传递INFINITE。
可以将0传递给S l e e p。这将告诉系统,调用线程将释放剩余的时间片,并迫使系统调度
另一个线程。可以将0传递给Sleep。这将告诉系统,调用线程将释放剩余的时间片,并迫使系统调度另一个线程。
7.4 线程切换
BOOL SwitchThread()
当调用这个函数的时候,系统要查看是否存在一个迫切需要 C P U时间的线程。如果没有线程迫切需要C P U时间,S w i t c h To T h r e a d就会立即返回。如果存在一个迫切需要C P U时间的线程,S w i t c h To T h r e a d就对该线程进行调度(该线程的优先级可能低于调用 S w i t c h To T h r e a d的线程) 。这个迫切需要C P U时间的线程可以运行一个时间段,然后系统调度程序照常运行。
7.5 线程的运行时间
BOOL GetThreadTimes(HADNLE hThread,PFILETIME pftCreationTime,PFILETIME pftExitTime,PFILETIME pftKernelTime,PFILETIME pftUserTime);
该函数返回4个不同的时间值。
可以通过使用下面的代码确定执行复杂的算法时需要的时间量:
GetProcessTimes适用于进程中的所有线程。
BOOL GetProcessTimes(HADNLE hProcess,PFILETIME pftCreationTime,PFILETIME pftExitTime,PFILETIME pftKernelTime,PFILETIME pftUserTime);
GetProcessTimes返回的时间适用于某个进程中的所有线程(甚至是已经终止运行的线程)。例如,返回的内核时间是所有进程的线程在内核代码中经过的全部时间的总和。
对于高分辨率的配置文件来说,GetProcessTimes并不完美。Windows确实提供了一些高分辨率性能函数:
使用如下:
/*Create a stopwatch timer*/
CStopwatch stopwatch;
//Excute the code I want to profile here
//Get how much time has elapsed up to now
__int64 qwElapsedTime = stopwatch.Now()
//qwElapsedTime indicates how long the profiled code executed in milliseconds
7.6 运行结构环境
CONTEXT结构包含主机CPU上的每个寄存器的数据结构。在x86计算机上,数据成员是EAX,EBX,ECX,EDX等。
typedef struct _CONTEXT{
//The flags values within this flag control the contents of a CONTEXT record
DWORD ContextFlags;
DWORD Dr0,Dr1,Dr2,Dr3,Dr4,Dr5,Dr6,Dr7;
FLOATING_SAVE_AREA FloatSave;
DWORD SegGes,SegFs,SegEs,SegDs;
DWORD Edi,Esi,Ebx,Edx,Ecx,Eax;
DWORD Ebp,Eip,SegCs,EFlags,Esp,SegSs;
BYTE ExtendRegisters[MAXINUM_SUPPORTED_EXTENSION];
}CONTEXT;
CONTEXTT结构可以分成若干个部分。CONTEXT_CONTROL包含CPU的控制寄存器,比如指令指针、堆栈指针、标志和函数返回地址(与x 8 6处理器不同,Alpya CPU在调用函数时,
将该函数的返回地址放入一个寄存器中) 。CONTEXT_INTEGET用于标识C P U的整数寄存器。CONTEXT_FLOATING_POINT用于标识C P U的浮点寄存器。CONTEXT_SEGMENTS用于标识C P U的段寄存器(仅为x 8 6处理器) 。CONTEXT_DEBUG_ REGISTER用于标识C P U的调试寄存器(仅为x 8 6处理器) 。CONTEXT_EXTENDED_ REGISTERS用于标识C P U的扩展寄存器(仅为x 8 6处理器) 。
BOOL GetThreadContext(HANDLE hThread,PCONTEXT pContext);获取当前CPU寄存器。
若要调用该函数,只需指定一个CONTEXTT结构,对某些标志(该结构的ContextFlags成员)进行初始化,指明想要收回哪些寄存器,并将该结构的地址传递给GetThreadContext。然后该函数将数据填入你要求的成员。
在调用GetThreadContext函数之前,应该调用SuspendThread,否则,线程可能被调度,而且线程的环境可能与你收回的不同。一个线程实际上有两个环境。一个是用户方式,一个是内核方式。GetThreadContext只能返回线程的用户方式环境。
CONTEXTT结构的ContextFlags成员并不与任何C P U寄存器相对应。无论是何种C P U结构,该成员存在于所有CONTEXT结构定义中。ContextFlags成员用于向GetThreadContext(函数指明你想检索哪些寄存器。
CONTEXT Context;
Context.ContextFlags = CONTEXT_CONTROL;//获取控制寄存器
Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;//获取控制寄存器和整数寄存器
Context.ContextFlags = CONTEXT_FULL //获取线程所有重要的寄存器
BOOL SetThreadContext(HANDLE hThread,CONST CONTEXT *pContext);修改CONTEXT结构中的成员。
同样,修改其环境的线程应该首先暂停,否则其结果将无法预测。
在调用SetThreadContext之前,必须再次对CONTEXT的ContextFlags成员进行初始化
7.7 线程的优先级
当设计一个应用程序时, 你应该考虑到还有什么别的应用程序会与你的应用程序一道运行。然后,应该根据你的应用程序中的线程应该具备何种响应性,选择一个优先级类。
只有当绝对必要的时候,才可以使用高优先级类。你会惊奇地发现, Windows Explorer是在高优先级上运行的。大多数时间E x p l o r e r的线程是暂停的,等待用户按下操作键或者点击鼠标按钮时被唤醒。当E x p l o r e r的线程处于暂停状态时,系统不将它的线程分配给 C P U。因为这将使低优先级线程得以运行。但是一旦用户按下一个操作键或组合键,如 C t r l + E s c,系统就会唤醒E x p l o r e r的线程(当用户按下C t r l + E s c组合键时,也会出现S t a r t菜单) 。如果低优先级线程正在运行,系统会立即抢在这些线程的前面,让E x p l o r e r的线程优先运行。
7.9 程序的优先级
创建子进程的进程负责选择子进程运行的优先级类。当使用E x p l o r e r来运行一个应用程序时,新进程按正常优先级运行。E x p l o r e r不知道进程在做什么,也不知道隔多长时间它的线程需要进行调度
4000
。但是,一旦子进程运行,它就能够通过调用S e t P r i o r i t y C l a s s来改变它自己的优先级类:
BOOL SetPriorityClass(HANDLE hProcess,DWORD fdwPriority);
DWORD GetPriorityClass(HANDLE hProcess);
BOOL SetThreadPriority(HANDLE hThread,int nPriority);
int GetThreadPriority(HANDLE hThread);
7.9.1 动态提高线程的优先级等级
BOOL SetProcessPriorityBoost(HANDLE hProcess,BOOL DisablePriorityBoost);
BOOL SetThreadPriorityBoost(HANDLE hThread,BOOL DisablePriorityBoost);
SetProcessPriorityBoost负责告诉系统激活或停用进行中的所有线程的优先级提高功能,而SetThreadPriorityBoost则让你激活或停用各个线程的优先级提高功能。
BOOL GetProcessPriorityBoost(HANDLE hProcess,BOOL DisablePriorityBoost);
BOOL GetThreadPriorityBoost(HANDLE hThread,BOOL DisablePriorityBoost);
7.9.2 为前台进程调整调度程序
在线程内核对象的内部有一个值,用于指明线程的暂停计数。
线程恢复运行
DWORD ResumeThread(HANDLE hThread);
ResumeThread函数运行成功,它将返回线程的前一个暂停计数,否则返回0xFFFFFFFF。
线程暂停运行
DWORD SuspendThread(HANDLE hThread);
任何线程都可以调用该函数来暂停另一个线程的运行(只要拥有线程的句柄) 。线程可以自行暂停运行,但是不能自行恢复运行。
线程暂停的最多次数可以是MAXINUM_SUSPEND_COUNT次(在Wi n N T. h中定义为1 2 7)
7.2 暂停和恢复进程的运行
对于Wi n d o w s来说,不存在暂停或恢复进程的概念,因为进程从来不会被安排获得 C P U时间。
Wi n d o w s确实允许一个进程暂停另一个进程中的所有线程的运行,但是从事暂停操作的进程必须是个调试程序。特别是,进程必须调用WaitForDebugEvent和ContinueDebugEvent之类的函数。
Wi n d o w s没有提供其他方法来暂停进程中所有线程的运行。
7.3 线程睡眠
VOID Sleep(DWORD dwMilliseconds);
该函数可使线程暂停自己的运行,直到dwMilliseconds过去为止。注意:
• 调用Sleep,可使线程自愿放弃它剩余的时间片。
• 系统将在大约的指定毫秒数内使线程不可调度
• 可以调用Sleep,并且为dwMilliseconds参数传递INFINITE。
可以将0传递给S l e e p。这将告诉系统,调用线程将释放剩余的时间片,并迫使系统调度
另一个线程。可以将0传递给Sleep。这将告诉系统,调用线程将释放剩余的时间片,并迫使系统调度另一个线程。
7.4 线程切换
BOOL SwitchThread()
当调用这个函数的时候,系统要查看是否存在一个迫切需要 C P U时间的线程。如果没有线程迫切需要C P U时间,S w i t c h To T h r e a d就会立即返回。如果存在一个迫切需要C P U时间的线程,S w i t c h To T h r e a d就对该线程进行调度(该线程的优先级可能低于调用 S w i t c h To T h r e a d的线程) 。这个迫切需要C P U时间的线程可以运行一个时间段,然后系统调度程序照常运行。
7.5 线程的运行时间
BOOL GetThreadTimes(HADNLE hThread,PFILETIME pftCreationTime,PFILETIME pftExitTime,PFILETIME pftKernelTime,PFILETIME pftUserTime);
该函数返回4个不同的时间值。
可以通过使用下面的代码确定执行复杂的算法时需要的时间量:
GetProcessTimes适用于进程中的所有线程。
BOOL GetProcessTimes(HADNLE hProcess,PFILETIME pftCreationTime,PFILETIME pftExitTime,PFILETIME pftKernelTime,PFILETIME pftUserTime);
GetProcessTimes返回的时间适用于某个进程中的所有线程(甚至是已经终止运行的线程)。例如,返回的内核时间是所有进程的线程在内核代码中经过的全部时间的总和。
对于高分辨率的配置文件来说,GetProcessTimes并不完美。Windows确实提供了一些高分辨率性能函数:
使用如下:
/*Create a stopwatch timer*/
CStopwatch stopwatch;
//Excute the code I want to profile here
//Get how much time has elapsed up to now
__int64 qwElapsedTime = stopwatch.Now()
//qwElapsedTime indicates how long the profiled code executed in milliseconds
7.6 运行结构环境
CONTEXT结构包含主机CPU上的每个寄存器的数据结构。在x86计算机上,数据成员是EAX,EBX,ECX,EDX等。
typedef struct _CONTEXT{
//The flags values within this flag control the contents of a CONTEXT record
DWORD ContextFlags;
DWORD Dr0,Dr1,Dr2,Dr3,Dr4,Dr5,Dr6,Dr7;
FLOATING_SAVE_AREA FloatSave;
DWORD SegGes,SegFs,SegEs,SegDs;
DWORD Edi,Esi,Ebx,Edx,Ecx,Eax;
DWORD Ebp,Eip,SegCs,EFlags,Esp,SegSs;
BYTE ExtendRegisters[MAXINUM_SUPPORTED_EXTENSION];
}CONTEXT;
CONTEXTT结构可以分成若干个部分。CONTEXT_CONTROL包含CPU的控制寄存器,比如指令指针、堆栈指针、标志和函数返回地址(与x 8 6处理器不同,Alpya CPU在调用函数时,
将该函数的返回地址放入一个寄存器中) 。CONTEXT_INTEGET用于标识C P U的整数寄存器。CONTEXT_FLOATING_POINT用于标识C P U的浮点寄存器。CONTEXT_SEGMENTS用于标识C P U的段寄存器(仅为x 8 6处理器) 。CONTEXT_DEBUG_ REGISTER用于标识C P U的调试寄存器(仅为x 8 6处理器) 。CONTEXT_EXTENDED_ REGISTERS用于标识C P U的扩展寄存器(仅为x 8 6处理器) 。
BOOL GetThreadContext(HANDLE hThread,PCONTEXT pContext);获取当前CPU寄存器。
若要调用该函数,只需指定一个CONTEXTT结构,对某些标志(该结构的ContextFlags成员)进行初始化,指明想要收回哪些寄存器,并将该结构的地址传递给GetThreadContext。然后该函数将数据填入你要求的成员。
在调用GetThreadContext函数之前,应该调用SuspendThread,否则,线程可能被调度,而且线程的环境可能与你收回的不同。一个线程实际上有两个环境。一个是用户方式,一个是内核方式。GetThreadContext只能返回线程的用户方式环境。
CONTEXTT结构的ContextFlags成员并不与任何C P U寄存器相对应。无论是何种C P U结构,该成员存在于所有CONTEXT结构定义中。ContextFlags成员用于向GetThreadContext(函数指明你想检索哪些寄存器。
CONTEXT Context;
Context.ContextFlags = CONTEXT_CONTROL;//获取控制寄存器
Context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;//获取控制寄存器和整数寄存器
Context.ContextFlags = CONTEXT_FULL //获取线程所有重要的寄存器
BOOL SetThreadContext(HANDLE hThread,CONST CONTEXT *pContext);修改CONTEXT结构中的成员。
同样,修改其环境的线程应该首先暂停,否则其结果将无法预测。
在调用SetThreadContext之前,必须再次对CONTEXT的ContextFlags成员进行初始化
7.7 线程的优先级
当设计一个应用程序时, 你应该考虑到还有什么别的应用程序会与你的应用程序一道运行。然后,应该根据你的应用程序中的线程应该具备何种响应性,选择一个优先级类。
只有当绝对必要的时候,才可以使用高优先级类。你会惊奇地发现, Windows Explorer是在高优先级上运行的。大多数时间E x p l o r e r的线程是暂停的,等待用户按下操作键或者点击鼠标按钮时被唤醒。当E x p l o r e r的线程处于暂停状态时,系统不将它的线程分配给 C P U。因为这将使低优先级线程得以运行。但是一旦用户按下一个操作键或组合键,如 C t r l + E s c,系统就会唤醒E x p l o r e r的线程(当用户按下C t r l + E s c组合键时,也会出现S t a r t菜单) 。如果低优先级线程正在运行,系统会立即抢在这些线程的前面,让E x p l o r e r的线程优先运行。
7.9 程序的优先级
创建子进程的进程负责选择子进程运行的优先级类。当使用E x p l o r e r来运行一个应用程序时,新进程按正常优先级运行。E x p l o r e r不知道进程在做什么,也不知道隔多长时间它的线程需要进行调度
4000
。但是,一旦子进程运行,它就能够通过调用S e t P r i o r i t y C l a s s来改变它自己的优先级类:
BOOL SetPriorityClass(HANDLE hProcess,DWORD fdwPriority);
DWORD GetPriorityClass(HANDLE hProcess);
BOOL SetThreadPriority(HANDLE hThread,int nPriority);
int GetThreadPriority(HANDLE hThread);
7.9.1 动态提高线程的优先级等级
BOOL SetProcessPriorityBoost(HANDLE hProcess,BOOL DisablePriorityBoost);
BOOL SetThreadPriorityBoost(HANDLE hThread,BOOL DisablePriorityBoost);
SetProcessPriorityBoost负责告诉系统激活或停用进行中的所有线程的优先级提高功能,而SetThreadPriorityBoost则让你激活或停用各个线程的优先级提高功能。
BOOL GetProcessPriorityBoost(HANDLE hProcess,BOOL DisablePriorityBoost);
BOOL GetThreadPriorityBoost(HANDLE hThread,BOOL DisablePriorityBoost);
7.9.2 为前台进程调整调度程序
相关文章推荐
- Windows内核之线程的调度,优先级,亲缘性
- Windows核心编程学习笔记 第二部分 完成编程任务 第7章 线程的调度 优先级 亲缘性
- Windows C/C++ 学习线程调度、线程优先级和亲缘性
- Windows via C/C++ 学习(15)线程调度、线程优先级和亲缘性
- Windows内核之线程的调度,优先级,亲缘性
- Windows核心编程 第七章 线程的调度、优先级和亲缘性(上)
- 第七章 线程的调度、优先级和亲缘性(4)
- posix多线程有感--线程高级编程(线程调度以及优先级设置)
- posix多线程有感--线程高级编程(优先级有关)
- Windows高级编程之线程与内核对象的同步
- posix多线程有感--线程高级编程(线程属性pthread_attr_t)---实时调度
- Windows核心编程<读书笔记七>线程的调度、优先级以及亲缘性 【含有代码】
- 第七章 线程的调度、优先级和亲缘性(5)
- posix多线程有感--线程高级编程(线程调度以及优先级设置)
- posix多线程有感--线程高级编程(进程的优先级)
- posix多线程有感--线程高级编程(优先级有关)
- posix多线程有感--线程高级编程(线程属性pthread_attr_t)---实时调度(代码)
- windows核心编程--线程高级
- Windows核心编程 第七章 线程的调度、优先级和亲缘性(下)
- posix多线程有感--线程高级编程(线程调度以及优先级设置)