线程操作函数
線程的掛起和恢復
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_FULL為CONTEXT_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。
轉載于:https://www.cnblogs.com/fwycmengsoft/p/6158130.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
- 上一篇: web.xml文件头出错
- 下一篇: 【Docker】Docker学习笔记:安