核心编程随笔7——线程调度和优先级 分类: VC++ 2013-09-29 08:44 606人阅读 评论(0) 收藏
2013-09-29 08:44
393 查看
NOTE0——何为上下文切换
每一个线程都有一个上下文。后者保存在线程的内核对象中。这个上下文反映了线程上一次执行时cpu寄存器的状态。大约每隔20ms(GetSystemTimeAdjustMent函数第二个参数的返回值),windows都会查看所有当前存在的线程内核对象,这些对象中只有一些是认为可以调度的。window在可调度的线程内核对象中选择一个,并将上次保存在线程上下文中的值载入cpu寄存器。这一操作成为上下文切换,可以通过spy++看线程属性。
说明:怎么确保某个线程在数据到达串行端口来的1MS之内开始运行。答案:不行。实时操作系统可以。但是window不是实时的。实时操作系统需要对底层的硬件有清楚的了解,从而指导硬盘控制器。键盘等的延时。
NOTE1——线程的挂起和恢复
有些线程对象的挂起技术大于0,这意味着该线程已经被挂起。不应该给他调度任何cpu时间。可以通过调用CreateProcess或CreateThread函数并传入CREATE_SUSPENDED标志来创建一个被挂起的线程。
可以通过调用ResumeThread函数。传入调用CreateThread时所返回的线程句柄来实现:
DWORDResumeThread(HandlehThread);如果成功返回线程前一个挂起计数。否则返回0xffffffff,还可以通过SuspendThread来挂起线程DWORDSuspendThread(HandlehThread);任何线程都可以调用这个函数挂起另一个线程,线程可以将自己挂起。但是他无法自己恢复。实际开发中。应用程序在调用suspendthread时必须小心。因为试图挂起一个线程时。我们不知道线程在做什么。例如线程正在分配堆中的内存。线程将锁定堆。当其他线程要访问堆的时候。他们的执行将被中止。直到第一个线程恢复。之后又在确切知道目标线程是哪个。而且采用完备的措施避免出现因挂起线程而引起的问或死锁的时候。调用suspendthread才是安全的。
openThread这个函数将找到线程ID匹配的线程内核对象。并将内核对象的使用计数递增1,然后返回对象的句柄。有了这个句柄。就可以调用suspendthread或resumethread了
NOTE2——切换到另一个线程
SwitchToThread的函数。如果存在另一个可调度线程。那么系统会让此线程运行。调用这个函数时。系统查看是否存在正急需cpu时间的饥饿线程。如果没有立即返回。如果存在.switchtothread将调用该线程。(该优先级可能比swithtothread的主调线程低),
NOTE3——在实际上下文中谈context结构。
系统使用context结构记住线程的状态。这样线程在下一次获得cpu可以运行时。就可以在上次停止处继续。window实际上允许我们查看线程内核对象的内部。并获得当前cpu寄存器状态的集合。为此。只需要调用GetThreadContext:调用它之前应该先调用suspendthread,否则。系统可能正好获得调度此线程。这样一来。线程的上下文和所获得的信息就不一致了。一个线程实际有两个上下文。用户模式和内核模式。GetThreadContext只能返回用户模式上下文。
通过setthreadcontext来改变结构中的成员。并把新的寄存器值放回线程的内核对象中。同样如果要改变哪个线程的上下文。应该要暂停该线程。否则结果无法预料。
#include"windows.h"
#include<TLHELP32.H>
#include"stdio.h"
#include"winnt.h"
voidSuspendProcess(DWORDdwProcessId,BOOLfsuspend);
intWINAPIWinMain(HINSTANCEhinstExe,HINSTANCE,
PSTRpszCmdLine,intnCmdShow)
{
HANDLEsnapshot;
PROCESSENTRY32processinfo;
processinfo.dwSize=sizeof(processinfo);
snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(snapshot==NULL)
returnFALSE;
BOOLstatus=Process32First(snapshot,&processinfo);
while(status)
{
if(stricmp("notepad.exe",processinfo.szExeFile)==0)
break;
status=Process32Next(snapshot,&processinfo);
}
if(status==0)
{
MessageBox(NULL,"没有找到你要挂起的进程","提示",MB_OK);
return1;
}
CloseHandle(snapshot);
SuspendProcess(processinfo.th32ProcessID,1);
SuspendProcess(processinfo.th32ProcessID,0);
return1;
}
voidSuspendProcess(DWORDdwProcessId,BOOLfsuspend)
{
HANDLEsnapshot;
snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
THREADENTRY32te={sizeof(te)};
BOOLfOK=Thread32First(snapshot,&te);
for(;fOK;fOK=Thread32Next(snapshot,&te))
{
if(te.th32OwnerProcessID==dwProcessId)
{
typedefHANDLE(__stdcall*OPENTHREAD)(DWORDdwFlag,BOOLbUnknow,DWORDdwThreadId);
HMODULEhDll=::LoadLibrary("Kernel32.dll");
OPENTHREADlpfnOpenThread=(OPENTHREAD)::GetProcAddress(hDll,"OpenThread");
HANDLEhThread=lpfnOpenThread(THREAD_SUSPEND_RESUME,FALSE,te.th32ThreadID);
//HANDLEhThread=lpfnOpenThread(THREAD_ALL_ACCESS,FALSE,te.th32ThreadID);
if(fsuspend==1)
{
SuspendThread(hThread);
CONTEXTcontext;
context.ContextFlags=CONTEXT_FULL;
GetThreadContext(hThread,&context);
context.Eip=0x00010000;
context.ContextFlags=CONTEXT_CONTROL;
SetThreadContext(hThread,&context);
}
else
ResumeThread(hThread);
//HANDLEhThread=OpenThread(THREAD_SUSPEND_RESUME,FALSE,te.th32OwnerProcessID);
}
}
CloseHandle(snapshot);
}
NOTE4——优先级编程
调用createprocess中可以在fdwcreate参数中传入需要的优先级。一旦进程运行。可以通过setpriorityclass来改变自己的优先级
SetPriorityClass进行设置
SetPriorityClass
设置优先权
函数原型:
BOOLSetPriorityClass(HANDLEhProcess,DWORDdwPriorityClass);
GetPriorityClass
得到优先权
函数原型:
DWORDGetPriorityClass(
HANDLEhProcess
);
dwPriorityClass:
ABOVE_NORMAL_PRIORITY_CLASS0x00008000
BELOW_NORMAL_PRIORITY_CLASS0x00004000
HIGH_PRIORITY_CLASS0x00000080
IDLE_PRIORITY_CLASS0x00000040
NORMAL_PRIORITY_CLASS0x00000020
REALTIME_PRIORITY_CLASS0x00000100
例:
if(!CreateProcess("D:\\ProgramFiles\\TTPlayer\\TTPlayer.exe",GetCommandLine(),NULL,
NULL,FALSE,CREATE_DEFAULT_ERROR_MODE|NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi))
{
CloseHandle(pi.hThread);
WaitForSingleObject(pi.hProcess,INFINITE);
CloseHandle(pi.hProcess);
}
BOOLfTemp=SetPriorityClass(pi.hProcess,HIGH_PRIORITY_CLASS);
//BOOLfTemp=SetPriorityClass(pi.hProcess,21);
LONGlRet=GetPriorityClass(pi.hProcess);
用来获取进程优先级的相应函数如下。getpriorityclass
NOTE5
SetProcessPriorityBoost允许或禁止系统提升一个进程中所有线程的优先级。
而SetThreadPriorityBoost则允许或禁止提升某个线程的优先级。有相应的Get函数来判断当前时候启用优先级提升。
SetFileInformationByHandle:Setsthefileinformationforthespecifiedfile.BOOLWINAPISetFileInformationByHandle(
__inHANDLEhFile,
__inFILE_INFO_BY_HANDLE_CLASSFileInformationClass,
__inLPVOIDlpFileInformation,
__inDWORDdwBufferSize
);
系统在启动时将确定计算机中存在多少个cpu。应用程序可以通过调用GetsystemInfo来查询机器上cpu的数量。如果限制某些进程只在可用cpu的一个子集上运行。则可以调用SetProcessAffinityMask
TheSetProcessAffinityMaskfunctionsetsaprocessoraffinitymaskforthethreadsofthespecifiedprocess.
BOOLSetProcessAffinityMask(
HANDLEhProcess,
DWORD_PTRdwProcessAffinityMask
);
//getsysteminfo
SYSTEM_INFOSystemInfo;
GetSystemInfo(&SystemInfo);
printf("
"
"dwNumberOfProcessors=%u,dwActiveProcessorMask=%u,wProcessorLevel=%u,
"
"wProcessorArchitecture=%u,dwPageSize=%u
",
SystemInfo.dwNumberOfProcessors,SystemInfo.dwActiveProcessorMask,SystemInfo.wProcessorLevel,
SystemInfo.wProcessorArchitecture,SystemInfo.dwPageSize
);
if(SystemInfo.dwNumberOfProcessors<=1)return;
DWORDdwMask=0x0000;
DWORDdwtmp=0x0001;
intnProcessorNum=0;
for(inti=0;i<32;i++)
//进程与指定cpu绑定
SetProcessAffinityMask(GetCurrentProcess(),dwMask);
//线程与指定cpu绑定
//SetThreadAffinityMask(GetCurrentThread(),dwMask);
return;
SetThreadAffinityMask是设置此线程只能在某个或某些处理器上运行;SetThreadIdealProcessor是在上述设置的范围内,指定线程优先在某个处理器上运行。
当vista在x86计算机上启动时。我们可以限制系统将所有的cpu数量。在启动过程中。系统将检查启动配置数据(BCD),BCD是一个取代老的boot.ini文本文件的数据存库,他在计算机的硬件和固件之上提供了一个抽象层。BCD的编程配置是通过wmi实现的。
每一个线程都有一个上下文。后者保存在线程的内核对象中。这个上下文反映了线程上一次执行时cpu寄存器的状态。大约每隔20ms(GetSystemTimeAdjustMent函数第二个参数的返回值),windows都会查看所有当前存在的线程内核对象,这些对象中只有一些是认为可以调度的。window在可调度的线程内核对象中选择一个,并将上次保存在线程上下文中的值载入cpu寄存器。这一操作成为上下文切换,可以通过spy++看线程属性。
说明:怎么确保某个线程在数据到达串行端口来的1MS之内开始运行。答案:不行。实时操作系统可以。但是window不是实时的。实时操作系统需要对底层的硬件有清楚的了解,从而指导硬盘控制器。键盘等的延时。
NOTE1——线程的挂起和恢复
有些线程对象的挂起技术大于0,这意味着该线程已经被挂起。不应该给他调度任何cpu时间。可以通过调用CreateProcess或CreateThread函数并传入CREATE_SUSPENDED标志来创建一个被挂起的线程。
可以通过调用ResumeThread函数。传入调用CreateThread时所返回的线程句柄来实现:
DWORDResumeThread(HandlehThread);如果成功返回线程前一个挂起计数。否则返回0xffffffff,还可以通过SuspendThread来挂起线程DWORDSuspendThread(HandlehThread);任何线程都可以调用这个函数挂起另一个线程,线程可以将自己挂起。但是他无法自己恢复。实际开发中。应用程序在调用suspendthread时必须小心。因为试图挂起一个线程时。我们不知道线程在做什么。例如线程正在分配堆中的内存。线程将锁定堆。当其他线程要访问堆的时候。他们的执行将被中止。直到第一个线程恢复。之后又在确切知道目标线程是哪个。而且采用完备的措施避免出现因挂起线程而引起的问或死锁的时候。调用suspendthread才是安全的。
openThread这个函数将找到线程ID匹配的线程内核对象。并将内核对象的使用计数递增1,然后返回对象的句柄。有了这个句柄。就可以调用suspendthread或resumethread了
NOTE2——切换到另一个线程
SwitchToThread的函数。如果存在另一个可调度线程。那么系统会让此线程运行。调用这个函数时。系统查看是否存在正急需cpu时间的饥饿线程。如果没有立即返回。如果存在.switchtothread将调用该线程。(该优先级可能比swithtothread的主调线程低),
NOTE3——在实际上下文中谈context结构。
系统使用context结构记住线程的状态。这样线程在下一次获得cpu可以运行时。就可以在上次停止处继续。window实际上允许我们查看线程内核对象的内部。并获得当前cpu寄存器状态的集合。为此。只需要调用GetThreadContext:调用它之前应该先调用suspendthread,否则。系统可能正好获得调度此线程。这样一来。线程的上下文和所获得的信息就不一致了。一个线程实际有两个上下文。用户模式和内核模式。GetThreadContext只能返回用户模式上下文。
通过setthreadcontext来改变结构中的成员。并把新的寄存器值放回线程的内核对象中。同样如果要改变哪个线程的上下文。应该要暂停该线程。否则结果无法预料。
#include"windows.h"
#include<TLHELP32.H>
#include"stdio.h"
#include"winnt.h"
voidSuspendProcess(DWORDdwProcessId,BOOLfsuspend);
intWINAPIWinMain(HINSTANCEhinstExe,HINSTANCE,
PSTRpszCmdLine,intnCmdShow)
{
HANDLEsnapshot;
PROCESSENTRY32processinfo;
processinfo.dwSize=sizeof(processinfo);
snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(snapshot==NULL)
returnFALSE;
BOOLstatus=Process32First(snapshot,&processinfo);
while(status)
{
if(stricmp("notepad.exe",processinfo.szExeFile)==0)
break;
status=Process32Next(snapshot,&processinfo);
}
if(status==0)
{
MessageBox(NULL,"没有找到你要挂起的进程","提示",MB_OK);
return1;
}
CloseHandle(snapshot);
SuspendProcess(processinfo.th32ProcessID,1);
SuspendProcess(processinfo.th32ProcessID,0);
return1;
}
voidSuspendProcess(DWORDdwProcessId,BOOLfsuspend)
{
HANDLEsnapshot;
snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
THREADENTRY32te={sizeof(te)};
BOOLfOK=Thread32First(snapshot,&te);
for(;fOK;fOK=Thread32Next(snapshot,&te))
{
if(te.th32OwnerProcessID==dwProcessId)
{
typedefHANDLE(__stdcall*OPENTHREAD)(DWORDdwFlag,BOOLbUnknow,DWORDdwThreadId);
HMODULEhDll=::LoadLibrary("Kernel32.dll");
OPENTHREADlpfnOpenThread=(OPENTHREAD)::GetProcAddress(hDll,"OpenThread");
HANDLEhThread=lpfnOpenThread(THREAD_SUSPEND_RESUME,FALSE,te.th32ThreadID);
//HANDLEhThread=lpfnOpenThread(THREAD_ALL_ACCESS,FALSE,te.th32ThreadID);
if(fsuspend==1)
{
SuspendThread(hThread);
CONTEXTcontext;
context.ContextFlags=CONTEXT_FULL;
GetThreadContext(hThread,&context);
context.Eip=0x00010000;
context.ContextFlags=CONTEXT_CONTROL;
SetThreadContext(hThread,&context);
}
else
ResumeThread(hThread);
//HANDLEhThread=OpenThread(THREAD_SUSPEND_RESUME,FALSE,te.th32OwnerProcessID);
}
}
CloseHandle(snapshot);
}
NOTE4——优先级编程
调用createprocess中可以在fdwcreate参数中传入需要的优先级。一旦进程运行。可以通过setpriorityclass来改变自己的优先级
SetPriorityClass进行设置
SetPriorityClass
设置优先权
函数原型:
BOOLSetPriorityClass(HANDLEhProcess,DWORDdwPriorityClass);
GetPriorityClass
得到优先权
函数原型:
DWORDGetPriorityClass(
HANDLEhProcess
);
dwPriorityClass:
ABOVE_NORMAL_PRIORITY_CLASS0x00008000
BELOW_NORMAL_PRIORITY_CLASS0x00004000
HIGH_PRIORITY_CLASS0x00000080
IDLE_PRIORITY_CLASS0x00000040
NORMAL_PRIORITY_CLASS0x00000020
REALTIME_PRIORITY_CLASS0x00000100
例:
if(!CreateProcess("D:\\ProgramFiles\\TTPlayer\\TTPlayer.exe",GetCommandLine(),NULL,
NULL,FALSE,CREATE_DEFAULT_ERROR_MODE|NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi))
{
CloseHandle(pi.hThread);
WaitForSingleObject(pi.hProcess,INFINITE);
CloseHandle(pi.hProcess);
}
BOOLfTemp=SetPriorityClass(pi.hProcess,HIGH_PRIORITY_CLASS);
//BOOLfTemp=SetPriorityClass(pi.hProcess,21);
LONGlRet=GetPriorityClass(pi.hProcess);
用来获取进程优先级的相应函数如下。getpriorityclass
NOTE5
SetProcessPriorityBoost允许或禁止系统提升一个进程中所有线程的优先级。
而SetThreadPriorityBoost则允许或禁止提升某个线程的优先级。有相应的Get函数来判断当前时候启用优先级提升。
SetFileInformationByHandle:Setsthefileinformationforthespecifiedfile.BOOLWINAPISetFileInformationByHandle(
__inHANDLEhFile,
__inFILE_INFO_BY_HANDLE_CLASSFileInformationClass,
__inLPVOIDlpFileInformation,
__inDWORDdwBufferSize
);
系统在启动时将确定计算机中存在多少个cpu。应用程序可以通过调用GetsystemInfo来查询机器上cpu的数量。如果限制某些进程只在可用cpu的一个子集上运行。则可以调用SetProcessAffinityMask
TheSetProcessAffinityMaskfunctionsetsaprocessoraffinitymaskforthethreadsofthespecifiedprocess.
BOOLSetProcessAffinityMask(
HANDLEhProcess,
DWORD_PTRdwProcessAffinityMask
);
//getsysteminfo
SYSTEM_INFOSystemInfo;
GetSystemInfo(&SystemInfo);
printf("
"
"dwNumberOfProcessors=%u,dwActiveProcessorMask=%u,wProcessorLevel=%u,
"
"wProcessorArchitecture=%u,dwPageSize=%u
",
SystemInfo.dwNumberOfProcessors,SystemInfo.dwActiveProcessorMask,SystemInfo.wProcessorLevel,
SystemInfo.wProcessorArchitecture,SystemInfo.dwPageSize
);
if(SystemInfo.dwNumberOfProcessors<=1)return;
DWORDdwMask=0x0000;
DWORDdwtmp=0x0001;
intnProcessorNum=0;
for(inti=0;i<32;i++)
//进程与指定cpu绑定
SetProcessAffinityMask(GetCurrentProcess(),dwMask);
//线程与指定cpu绑定
//SetThreadAffinityMask(GetCurrentThread(),dwMask);
return;
SetThreadAffinityMask是设置此线程只能在某个或某些处理器上运行;SetThreadIdealProcessor是在上述设置的范围内,指定线程优先在某个处理器上运行。
当vista在x86计算机上启动时。我们可以限制系统将所有的cpu数量。在启动过程中。系统将检查启动配置数据(BCD),BCD是一个取代老的boot.ini文本文件的数据存库,他在计算机的硬件和固件之上提供了一个抽象层。BCD的编程配置是通过wmi实现的。
相关文章推荐
- 核心编程随笔5 分类: VC++ 2013-09-28 08:44 562人阅读 评论(0) 收藏
- 核心编程随笔4 分类: VC++ 2013-09-28 08:44 579人阅读 评论(0) 收藏
- 核心编程随笔1 分类: VC++ 2013-09-28 08:42 558人阅读 评论(0) 收藏
- 核心编程6——线程 分类: VC++ 2013-09-29 08:43 521人阅读 评论(0) 收藏
- 核心编程随笔3 分类: VC++ 2013-09-28 08:43 487人阅读 评论(0) 收藏
- 核心编程随笔2 分类: VC++ 2013-09-28 08:43 518人阅读 评论(0) 收藏
- 核心编程笔记9——内核对象的线程同步2 分类: VC++ 2013-09-29 08:45 488人阅读 评论(0) 收藏
- Winsock编程基础介绍 . 分类: VC++ 2013-09-14 17:30 512人阅读 评论(0) 收藏
- HeapAlloc,GlobalAlloc,LocalAlloc,VirtualAlloc,malloc,new的异同 分类: VC++ 2013-09-29 08:48 547人阅读 评论(0) 收藏
- 四种进程或线程同步互斥的控制方法 分类: VC++ 2013-09-29 08:48 507人阅读 评论(0) 收藏
- VC++信息安全编程(13)Windows2000/xp/vista/7磁盘扇区读写技术 分类: 磁盘的扇区读写 VC++ 2015-04-29 10:38 357人阅读 评论(0) 收藏
- FAT32文件系统的存储组织结构(一) 分类: VC++ 2014-08-27 08:40 504人阅读 评论(0) 收藏
- win9x_win2k下对物理磁盘的操作 分类: VC++ 磁盘的扇区读写 2014-08-27 09:55 421人阅读 评论(0) 收藏
- ucos在s3c2410上运行过程整体剖析之基础知识-与UCOS运行有关的ARM9芯片知识 分类: μc /os ii 系统有关知识 2012-03-08 21:23 606人阅读 评论(0) 收藏
- 核心编程随笔7——线程调度和优先级
- 进程中调用CreateMutex 分类: VC++ 2013-10-09 09:13 599人阅读 评论(0) 收藏
- AM335x(TQ335x)学习笔记——GPIO按键驱动移植 分类: TI-AM335X 2015-05-22 08:44 144人阅读 评论(0) 收藏
- 【原创】《Linux高级程序设计》杨宗德著 - Linux Socket网络编程基础 - 网络通信基础 分类: Linux --- 应用程序设计 2014-12-03 22:46 71人阅读 评论(0) 收藏
- 【原创】《Linux高级程序设计》杨宗德著 - Linux Socket网络编程基础 - 网络调试工具 分类: Linux --- 应用程序设计 2014-12-05 17:19 84人阅读 评论(0) 收藏
- ios开发之网络编程 分类: ios开发 2014-12-09 15:18 146人阅读 评论(0) 收藏