注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

从C开始

 
 
 

日志

 
 

《Windows核心编程》学习笔记(13)– 详解线程  

2010-10-15 18:18:01|  分类: 《Windows核心编 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

线程的挂起和恢复

DWORD SuspendThread ( HANDLE hThread );   //挂起线程

DWORD ResumeThread ( HANDLE hThread );   //恢复线程

 

SuspendThread ResumeThread 都返回之前的挂起计数。

 

一个线程最多可以挂起MAXIMUM_SUSPEND_COUNT (WinNT.h中定义为127)

 

进程的挂起和恢复

对于Windows来说,不存在暂停或恢复进程的概念,因为进程从来不会被安排获得cpu时间。

但是我们可以创建一个函数,用来挂起或者恢复进程中的全部线程,这样就能挂起或者恢复一个进程了。

 

参考代码如下:

 

#include <Windows.h>

#include <stdio.h>

#include <Tlhelp32.h>

 

//dwProcessID参数为需要挂起或者恢复的进程ID

// bSuspend参数如果为TRUE就挂起进程,否则恢复进程

void SuspendProcess(DWORD dwProcessID, BOOL bSuspend)

{

         HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwProcessID);

 

         if (hSnapshot != INVALID_HANDLE_VALUE)

         {

                   THREADENTRY32 te;

                   ZeroMemory(&te, sizeof(te));

                   te.dwSize = sizeof(te);

 

                   BOOL bOK = Thread32First(hSnapshot, &te);

                   for (; bOK; bOK = Thread32Next(hSnapshot, &te))

                   {

                            if (te.th32OwnerProcessID == dwProcessID)

                            {

                                     HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, te.th32ThreadID);

                                     if (hThread != NULL)

                                     {

                                               if (bSuspend)

                                               {

                                                        SuspendThread(hThread);

                                               }

                                               else

                                                        ResumeThread(hThread);

                                              

                                     }

                                     CloseHandle(hThread);

                            }

                   }

         }

         CloseHandle(hSnapshot);

}

int main(void)

{

         SuspendProcess(9636, FALSE);

 

         return 0;

}

 

睡眠

VOID Sleep (DWORD dwMilliseconds);

 

这个函数将使线程自己挂起 dwMilliseconds 长的时间。

 

1.       调用Sleep,可使线程自愿放弃它剩余的时间片。

 

2. 系统将在大约的指定毫秒数内使线程不可调度。不错,如果告诉系统,想睡眠                               100ms,那么可以睡眠大约这么长时间,但是也可能睡眠数秒钟或者数分钟。记住,                              Windows不是个实时操作系统。虽然线程可能在规定的时间被唤醒,但是它能否做到,取决于系统中还有什么操作正在进行。

 

3.可以调用Sleep,并且为dwMilliseconds参数传递INFINITE。这将告诉系统永远不要调度该线程。这不是一件值得去做的事情。最好是让线程退出,并还原它的堆栈和内核对象。

 

4. 可以将0传递给Sleep。这将告诉系统,调用线程将释放剩余的时间片,并迫使系统调度另一个线程。但是,系统可以对刚刚调用 Sleep的线程重新调度。如果不存在多个拥有相同优先级的可调度线程,就会出现这种情况。

 

切换到另一个线程

BOOL SwitchToThread ();

 

当调用这个函数的时候,系统要查看是否存在一个迫切需要CPU时间的线程。如果没有线程迫切需要CPU时间,SwitchToThread就会立即返回。如果存在一个迫切需要 CPU时间的线程,SwitchToThread就对该线程进行调度(该线程的优先级可能低于调用 SwitchToThread的线程)。

这个迫切需要CPU时间的线程可以运行一个时间段,然后系统调度程序照常运行。该函数允许一个需要资源的线程强制另一个优先级较低、而目前却拥有该资源的线程放弃该资源。如果调用 SwitchToThread函数时没有其他线程能够运行,那么该函数返回 FALSE,否则返回一个非0值。

调用SwitchToThread 函数与调用一个 0ms 超时的Sleep函数是相似的。差别是SwitchToThread允许优先级较低的线程运行。而Sleep会立即对调用线程重新进行调度即使低优先级线程迫切需要 CPU时间。

 

在实际上下文中谈CONTEXT结构

CONTEXT结构可以分成若干个部分。

CONTEXT_CONTROL包含CPU的控制寄存器,比如指令指针、堆栈指针、标志和函数返回地址。

CONTEXT_INTEGER用于标识CPU 的整数寄存器。

CONTEXT_FLOAFTING_POINT用于标识C P U的浮点寄存器。

CONTEXT_SEGMENTS用于标识 CPU 的段寄存器。

CONTEXT_DEBUG_ REGISTER用于标识CPU 的调试寄存器。

CONTEXT_EXTENDED_ REGISTERS用于标识CPU的扩展寄存器。

 

我们可以使用GetThreadContext函数来查看线程内核对象的内部,并获取当前CPU寄存器状态的集合。

 

BOOL GetThreadContext (

HANDLE  hThread,

PCONTEXT  pContext)

 

若要调用该函数,只需指定一个CONTEXT结构,对某些标志(该结构的ContextFlags成员)进行初始化,指明想要收回哪些寄存器,并将该结构的地址传递给GetThreadContext 。然后该函数将数据填入你要求的成员。

在调用GetThreadContext函数之前,应该调用SuspendThread,否则,线程可能刚好被调度,这样一来,线程的上下文就和所获取的信息不一致了。

 

示例代码如下:

 

//定义一个CONTEXT结构

         CONTEXT Context;

         //告诉系统我们想获取线程控制寄存器的内容

         Context.ContextFlags = CONTEXT_CONTROL;

         //调用GetThreadContext获取相关信息

         GetThreadContext(hThread, &Context);

 

Ps:在调用GetThreadContext函数之前,必须首先初始化CONTEXT结构的ContextFlags成员。

要获得线程的所有重要的寄存器(也就是微软认为最常用的寄存器),应该像下面一样初始化ContextFlags

 

Context.ContextFlags = CONTEXT_FULL;

 

WinNT. h头文件中,定义了CONTEXT_FULLCONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS

 

 

当然,我们还可以通过调用SetThreadContext函数来改变结构中的成员,并把新的寄存器值放回线程的内核对象中:

 

BOOL SetThreadContext (

HANDLE  hThread,

CONST CONTEXT  *pContext)

 

同样,如果要改变哪个线程的上下文,应该先暂停该线程。

 

         //定义一个CONTEXT结构

         CONTEXT Context;

         //挂起线程

         SuspendThread(hThread);

         //获取当前上下文的值

         Context.ContextFlags = CONTEXT_CONTROL;

         GetThreadContext(hThread, &Context);

         //Eip字段存储的是指令指针,现在让指令指针指向地址 0x00010000

         Context.Eip = 0x00010000;

         Context.ContextFlags = CONTEXT_CONTROL;

         //重新设置线程上下文

         SetThreadContext(hThread, &Context);

         //恢复线程,现在线程开始从0x00010000这个地方开始执行指令

         ResumeThread(hThread);

 

 

线程的优先级

 2010年10月15日 - fly - y1生倾于晴


一旦进程运行,便可以通过调用SetPriorityClass来改变自己的优先级

 

BOOL SetPriorityClass(

         HANDLE  hProcess

         DWORD  fdwPriority);

 

用来获取进程优先级:

 

DWORD GetPriorityClass( HANDLE  hProcess );

 

设置和获取线程的相对优先级:

 

BOOL SetThreadPriority (

         HANDLE  hThread,

         Int  nPriority);

 

Int GetThreadPriority(HANDLE  hThread);

 

允许或者禁止进程或者线程动态提升自己的优先级:

 

BOOL SetProcessPriorityBoost(

         HANDLE  hProcess,

         BOOL  bDisablePriorityBoost);

 

 BOOL SetThreadPriorityBoost(

         HANDLE  hThread,

         BOOL  bDisablePriorityBoost);

 

判断当前是不是启用优先级提升:

 

BOOL GetProcessPriorityBoost(

         HANDLE  hProcess,

         PBOOL  pbDisablePriorityBoost);

 

 BOOL GetThreadPriorityBoost(

         HANDLE  hThread,

         PBOOL  pbDisablePriorityBoost);

 

在多CPU的情况下,我们可以限制某些线程只在可用的cpu的一个子集上运行:

 

BOOL SetProcessAffinityMask(

         HANDLE  hProcess

         DWORD_PTR  dwProcessAffinityMask);

 

第一个参数hProcess代表要设置的进程。第二个参数dwProcessAffinityMask是一个位掩码,代表线程可以在哪些CPU上运行。例如,传入0x00000005意味着这个进程中的线程可以在CPU 0 CPU 2上运行,但是不能在CPU 1 CPU 3~31上运行。

 

获取进程的关联性掩码:

 

BOOL GetProcessAffinityMask(

         HANDLE  hProcess

         PDWORD_PTR  pdwProcessAffinityMask,

PDWORD_PTR  pdwSystemAffinityMask);

 

设置线程的关联性掩码:

 

BOOL SetThreadAffinityMask(

         HANDLE  hThread

         DWORD_PTR  dwThreadAffinityMask);

 

有时候强制一个线程只是用特定的某个CPU并不是什么好主意。例如,如果有三个线程都只能使用CPU0,而CPU1CPU2CPU3却无所事事。我们想让一个线程运行在一个CPU上,但是同时系统也允许他移到另一个空闲的CPU,那就更好了。要给线程设置一个理想的CPU,可以调用如下:

 

DWORD SetThreadIdealProcessor(

         HANDLE  hThread,

         DWORD  dwIdealProcessor);

 

hThread用于指明要为哪个线程设置首选CPU

dwIdealProcessor函数不是个位掩码,它是个从031/63,用于指明供线程希望使用的首选CPU 。可以传递一个MAXIMUM_PROCESSORS的值(在WinNT.h中定义,在32位操作系统中定义为3264位操作系统中定义为64),表明线程没有理想的CPU。如果没有为该线程设置理想的CP U,那么该函数返回前一个理想的CPUMAXIMUM_PROCESSORS

  评论这张
 
阅读(731)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018