線程操作函數


線程的掛起和恢復

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的線程重新調度。Sleep(0)是指CPU交出當前線程的執行權,讓CPU去執行其他線程。也就是放棄當前線程的時間片,轉而執行其他線程

 

切換到另一個線程

BOOL SwitchToThread (void);

當調用這個函數的時候,系統要查看是否存在一個迫切需要CPU時間的線程。如果沒有線程迫切需要CPU時間,SwitchToThread就會立即返回。如果存在一個迫切需要 CPU時間的線程,SwitchToThread就對該線程進行調度(該線程的優先級可能低於調用 SwitchToThread的線程)。

這個迫切需要CPU時間的線程可以運行一個時間段,然后系統調度程序照常運行。該函數允許一個需要資源的線程強制另一個優先級較低、而目前卻擁有該資源的線程放棄該資源。如果調用 SwitchToThread函數時沒有其他線程能夠運行,那么該函數返回 FALSE,否則返回一個非0值。

Sleep():時間片只能讓給優先級相同或更高的線程;

SwitchToThread():只要有可調度線程,即便優先級較低,也會讓其調度。

 

在實際上下文中談CONTEXT結構

CONTEXT結構包括以下部分:

   CONTEXT_CONTROL:包含CPU的控制寄存器,比如指今指針,堆棧指針,標志和函數返回地址..AX, BX, CX, DX, SI, D
     CONTEXT_INTEGER:用於標識CPU的整數寄存器.DS, ES, FS, GS
   CONTEXT_FLOATING_POINT:用於標識CPU的浮點寄存器.
     CONTEXT_SEGMENTS:用於標識CPU的段寄存器.SS:SP, CS:IP, FLAGS, BP
   CONTEXT_DEBUG_REGISTER:用於標識CPU的調試寄存器.  
   CONTEXT_EXTENDED_REGISTERS:用於標識CPU的擴展寄存器I
   CONTEXT_FULL:相當於CONTEXT_CONTROL or CONTEXT_INTEGER or   CONTEXT_SEGMENTS,即這三個標志的組合

 

 

我們可以使用GetThreadContext函數來查看線程內核對象的內部,並獲取當前CPU寄存器狀態的集合。

BOOL GetThreadContext (

HANDLE  hThread,

PCONTEXT  pContext)

若要調用該函數,只需指定一個CONTEXT結構,對某些標志(該結構的ContextFlags成員)進行初始化,指明想要收回哪些寄存器,並將該結構的地址傳遞給GetThreadContext 。然后該函數將數據填入你要求的成員。

在調用GetThreadContext函數之前,應該調用SuspendThread,否則,線程可能剛好被調度,這樣一來,線程的上下文就和所獲取的信息不一致了。

示例代碼如下: 

         CONTEXT Context;                  //定義一個CONTEXT結構

 

         Context.ContextFlags = CONTEXT_CONTROL;    //告訴系統我們想獲取線程控制寄存器的內容   

         GetThreadContext(hThread, &Context);      //調用GetThreadContext獲取相關信息

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);

 

         Context.Eip = 0x00010000;      //Eip字段存儲的是指令指針,現在讓指令指針指向地址 0x00010000;

         Context.ContextFlags = CONTEXT_CONTROL;

 

         SetThreadContext(hThread, &Context);   //重新設置線程上下文

 

         ResumeThread(hThread);         //恢復線程,現在線程開始從0x00010000這個地方開始執行指令

 

線程的優先級

優先級為0的線程:系統啟動時,會創建一個優先級為0的“頁面清零線程”,它只有在系統中沒有其他可調度線程時,才能調度,用來清除內存中的閑置頁面。

優先級在1 ~ 15之間的線程:一般用戶模式下,線程的優先級都在該范圍。

優先級在16 ~ 30之間的線程:一般是內核線程。

 

一旦進程運行,便可以通過調用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,而CPU1,CPU2和CPU3卻無所事事。我們想讓一個線程運行在一個CPU上,但是同時系統也允許他移到另一個空閑的CPU,那就更好了。要給線程設置一個理想的CPU,可以調用如下:

DWORD SetThreadIdealProcessor(

         HANDLE  hThread,

         DWORD  dwIdealProcessor);

hThread用於指明要為哪個線程設置首選CPU。

dwIdealProcessor函數不是個位掩碼,它是個從0到31/63,用於指明供線程希望使用的首選CPU 。可以傳遞一個MAXIMUM_PROCESSORS的值(在WinNT.h中定義,在32位操作系統中定義為32,64位操作系統中定義為64),表明線程沒有理想的CPU。如果沒有為該線程設置理想的CPU,那么該函數返回前一個理想的CPU或MAXIMUM_PROCESSORS。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM