【第17節】windows sdk編程:線程與線程調度

目錄

一、線程

1.1 線程的基本概念

1.2 何時創建線程

二、線程控制

三、遍歷線程

四、線程內核對象

4.1 線程上下文

4.2 暫停次數

4.3 信號

五、線程調度

5.1 什么是線程優先級

5.2 進程優先級與相對線程優先級

5.3 編程改變優先級

5.4 動態優先級的概念


一、線程

1.1 線程的基本概念

????????線程是進程中的一個獨立控制流,它是程序運行時的調度單位,也是執行代碼的基本單元。從 CPU 的角度來看,所有線程都是平等的,不會因為屬于某個進程而受到特殊對待。CPU 根據線程的優先級來決定執行哪個線程,并分配相應的時間片。當一個線程的時間片用完時,CPU 會切換到下一個線程繼續執行。?

????????通常情況下,線程執行的代碼屬于某個進程,同一個進程中的所有線程共享進程的資源,包括虛擬內存空間、內核對象句柄表等。

????????此外,還有一種內核線程,它的代碼完全在內核空間中運行,不在我們當前的討論范圍內。每個線程都是一個獨立的執行單元。

1.2 何時創建線程

通常在以下情況下需要創建線程:
- 在輸入的同時需要輸出(例如在顯示界面的同時處理數據);
- 邏輯A的執行依賴于邏輯B的實時反饋(比如進度條的更新);
- 利用計算機的空閑時間處理一些繁重但不緊急的任務;
- 涉及大量磁盤操作的程序;
- 與網絡操作相關的程序;
- 需要處理多個長時間等待的業務邏輯;
- 需要進行密集計算,并充分利用多核CPU性能的程序;
- 需要讓其他進程執行自己的代碼時(例如遠程注入代碼);

????????簡單來說,當某些操作可能會阻塞當前線程,而當前線程又非常重要不能被阻塞時,就需要創建新的線程。

二、線程控制

相關的線程控制函數如下:
- `CreateProcess`:創建進程。
- `OpenProcess`:打開進程。
- `ExitProcess`:退出本進程。
- `TerminateProcess`:結束其他進程。
- `SuspendThread`:暫停線程(掛起)。
- `ResumeThread`:恢復線程。

創建線程示例代碼:

#include "stdafx.h"
#include <windows.h>
int g_nNum = 0;DWORD WINAPI ThreadProc(LPVOID lParam) {printf("我是線程!\n");for (int i=0;i<1000;i++){g_nNum++;}printf("%d\n", g_nNum);return 0;
}int main()
{CreateThread(NULL, NULL, ThreadProc, NULL, 0, NULL);CreateThread(NULL, NULL, ThreadProc, NULL, 0, NULL);system("pause");printf("%d\n", g_nNum);return 0;
}

三、遍歷線程

????????線程的遍歷同樣可以使用創建快照的方式,以下是遍歷某一個進程線程的示例代碼:

VOID ListProcessThreads(DWORD dwPID) {HANDLE hThreadSnap = INVALID_HANDLE_VALUE;THREADENTRY32 te32;//創建快照,當前操作系統的線程快照hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);if (hThreadSnap == INVALID_HANDLE_VALUE)return;//設置輸入參數,結構的大小te32.dwSize = sizeof(THREADENTRY32);//開始獲取信息if (!Thread32First(hThreadSnap, &te32)) {CloseHandle(hThreadSnap);   //關閉句柄return;}do {if (te32.th32OwnerProcessID == dwPID) {//顯示相關信息printf("\n THREAD ID=0x%08X", te32.th32ThreadID);printf("\t base priority =%d", te32.tpBasePri);printf("\t delta priority =%d", te32.tpDeltaPri);}} while (Thread32Next(hThreadSnap, &te32));CloseHandle(hThreadSnap);
}

????????這段代碼的功能是列出指定進程id(通過 dwPID 參數標識)的所有線程信息。它使用了 Windows API 中的 Toolhelp32?系列函數來遍歷系統中的線程,并輸出每個線程的?ID?和優先級信息。?

四、線程內核對象

????????線程的創建伴隨著在內核中創建一個線程內核對象的過程,在線程內核對象的數據結構中包含了一些重要信息。

4.1 線程上下文

????????對于CPU來說,系統里有大量線程等著被執行。CPU會依據線程的優先級,來決定先執行哪個線程,并且在執行前給它分配一定的時間片。當正在執行的線程把時間片用完了,CPU就會切換去執行其他線程,就這樣循環往復,讓操作系統里的線程都有機會依次執行。而在這個切換線程的過程中,就會涉及到線程環境的保存和加載操作。?

????????具體來講,當一個線程暫時不使用CPU了,它得把自己當前的執行環境保存起來,這樣下次再輪到它執行的時候,就能接著之前的狀態繼續。相反,當一個線程即將要被CPU執行時,得先把它對應的執行環境加載到CPU里。?

????????在線程的內核對象中,存在一個結構體專門用來存儲當前線程的執行環境。在用戶層面,我們可以借助特定的API來獲取和設置線程環境 。?

?

獲取線程環境的函數:

BOOL WINAPI GetThreadContext(_In_ HANDLE hThread,_Inout_ LPCONTEXT lpContext
);

?

設置線程環境的函數:

BOOL WINAPI SetThreadContext(_In_ HANDLE hThread,_In_ CONST CONTEXT* lpContext
);

`CONTEXT`結構體定義如下:

typedef struct _CONTEXT {DWORD ContextFlags;DWORD   Dr0;DWORD   Drl;DWORD    Dr2;DWORD   Dr3;DWORD   Dr6;DWORD   Dr7;FLOATING_SAVE_AREA FloatSave;DWORD   SegGs;DWORD  SegFs;DWORD  SegEs;DWORD  SegDs;DWORD  Edi;DWORD  Esi;DWORD  Ebx;DWORD  Edx;DWORDDWORDDWORDDWORDDWORDDWORDDWORDDWORDBYTE }CONTEXT;Ecx;Eax;Ebp;Eip;SegCs;  EFlags;Esp;SegSs;ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];

????????可以看出,線程環境基本就是CPU在執行此線程時的寄存器信息。

4.2 暫停次數

????????一個線程能夠被暫停,且能被暫停多次。一個線程被暫停的次數在線程的內核對象中有記錄,每暫停一次線程,暫停次數自增,每恢復一次線程,暫停次數自減,只有暫停次數為0的時候,線程才會運行起來。

4.3 信號

在創建和等待線程時會涉及信號的概念。例如:

//創建一個線程
HANDLE hThread = INVALID_HANDLE_VALUE;
CreateThread(NULL, NULL, Proc, NULL, NULL, NULL);//等待線程結束
WaitForSingleObject(hThread, -1);
//關閉句柄
CloseHandle(hThread);

????????信號其實就是線程自身的一種狀態。有個`WaitForSingleObject`函數,它專門用來檢查這個信號狀態。要是信號狀態是`FALSE` ,也就是沒有信號,處于非激發態,那`WaitForSingleObject`函數就會一直等著。而一旦信號狀態變成`TRUE`,也就是有信號,處于激發態了,這個函數就會馬上返回。就拿線程來說,當線程運行結束的時候,它的信號狀態就會從沒有信號的狀態轉變成有信號的狀態。這時候,`WaitForSingleObject`函數就能等到線程結束,然后返回,程序也就可以接著去執行后續的代碼了。?

????????不光線程是可等待的,還有很多內核對象也是可以等待的,如下表:

五、線程調度

5.1 什么是線程優先級

(1)每個線程都有一個優先級數值,范圍從0(最低)到31(最高)。

(2)當一個線程把分配給它的時間片用完了,系統就得決定接下來給哪個線程分配時間片。這時,系統會從優先級最高的線程開始,依次往低優先級查看,優先讓高優先級的線程得到執行機會。?

(3)要是有個低優先級的線程正在運行,可恰好有高優先級的線程已經準備好要執行了,那系統就會馬上中斷低優先級線程,轉而給高優先級線程分配時間片,讓高優先級線程運行起來。比如說,只要系統里存在優先級為31的線程,那系統就不會去執行那些優先級在0到30之間的線程。

(4)系統剛啟動的時候,會有一個特殊的線程,它的優先級是0 ,這個線程專門負責把系統內存里所有閑置的頁面都清零,而且整個系統里只有這一個優先級為0的線程 。

5.2 進程優先級與相對線程優先級

????????在Windows系統里,我們沒辦法直接去調整線程的優先級。Windows采用了一種間接的辦法,它依據進程優先級以及相對線程優先級,讓操作系統自己來算出線程優先級具體是多少。

????????進程優先級有這么幾種類型,分別是`real-time`(實時)、`high`(高)、`above normal`(高于標準)、`normal`(標準)、`below normal`(低于標準)、`idle`(最低) 。

????????進程優先級就像是給這個進程里所有線程的優先級定了個大方向。之后,再結合相對線程優先級,就能確定線程真正的優先級數值。

????????這里要特別注意,線程優先級是相對進程優先級而言的。要是你更改了進程優先級,雖然線程的相對優先級不會變,但是它實際的優先級數值卻是會跟著改變的 。

5.3 編程改變優先級

1. 當我們使用`CreateProcess`函數創建進程時,能在它的`fdwCreate`參數里設置優先級。
2. 要是想改變進程的優先級,還可以用`SetPriorityClass`這個函數來實現。
3. 要是想知道某個進程的優先級是多少,就得調用`GetPriorityClass`函數。
4. 注意,`CreateThread`函數沒有設置線程相對優先級的參數,不能通過它來設置線程相對優先級。
5. 要設置線程的優先級,得使用`SetThreadPriority`函數。
6. 要是想獲取線程的相對優先級,就得調用`GetThreadPriority`函數。

5.4 動態優先級的概念

1. 由進程優先級和線程優先級算出來的優先級,我們叫它基本優先級。有時候,系統會自動提高某個線程的優先級,這么做主要有兩個原因:
??????? (1)為了能快點響應一些緊急操作。
??????? (2)給那些一直沒機會執行、處于“饑餓”狀態的線程分配時間片。
2. 這里有幾點要注意:
????????(1)優先級被提高的線程,在得到時間片去執行后,它的優先級數值會自動減小,一直減到基本優先級就不再減了。
????????(2)如果一個“饑餓”線程有2到3秒都沒執行,它的優先級會臨時變為15,等它執行完兩個時間片后,優先級又會變回原來的數值。
????????(3)系統自動提升優先級的范圍是1到15,優先級在16到31之間的線程,系統不會去提升它們的優先級。
????????(4)我們能阻止系統提升優先級:
????????- 使用`SetProcessPriorityBoost()`函數,能禁止提升當前進程里線程的優先級。
??????? - 使用`SetThreadPriorityBoost()`函數,能禁止提升某個線程的優先級。
??????? - 要是想知道進程或線程有沒有使用優先級提升功能,可以用`GetProcessPriorityBoost`和`GetThreadPriorityBoost`這兩個函數來判斷 。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/72838.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/72838.shtml
英文地址,請注明出處:http://en.pswp.cn/web/72838.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python數據可視化實戰:從基礎圖表到高級分析

Python數據可視化實戰&#xff1a;從基礎圖表到高級分析 數據可視化是數據分析的重要環節&#xff0c;通過直觀的圖表可以快速洞察數據規律。本文將通過5個實際案例&#xff0c;手把手教你使用Python的Matplotlib庫完成各類數據可視化任務&#xff0c;涵蓋條形圖、堆積面積圖、…

【機器學習-分類算法】

比如將一張圖片按尺寸識別分類為橫向或者縱向兩類就是二分類問題 設x軸為圖像的寬、y軸為圖像的高&#xff0c;那么把訓練數據展現在圖上就是這樣的: 若增加更多的數據集有: 如果只用一條線將圖中白色的點和黑色的點分開,那么: 分類的目的就是找到這條線,就可以根據點在線…

Compose Indication:點擊效果設置

Compose Indication&#xff1a;打造獨特點擊效果的秘密武器 在Compose開發中&#xff0c;大家可能都碰到過Indication&#xff0c;不少人第一次接觸它&#xff0c;是在想去掉Material默認的點擊水波紋效果的時候。要是在AI工具里搜“怎么去掉水波紋效果”&#xff0c;會得到這…

Docker build 會在本地產生巨大的文件

Docker build 會在本地產生巨大的文件&#xff0c; 比如 用 這個命令列出本地鏡像 docker images 可見size都是很大的&#xff0c; 到docker目錄下&#xff0c;看到ext4.vhdx的大小 80多G 那只能用這個命令把不用的鏡像刪掉了&#xff1a; &#xff08;rmi后面是鏡像id&a…

臺式機電腦組裝---電腦機箱與主板接線

臺式機電腦組裝—電腦機箱與主板接線 1、機箱連接主板的跳線一般主要有USB 2.0、USB 3.0、前置音頻接口(HD_AUDIO)以及POWER SW、RESET SW、POWER LED、HDD LED四個主板跳線&#xff0c;這些跳線分別的含義如下。 RESET SW&#xff1a;機箱重啟按鍵&#xff1b;注&#xff1a…

【虛幻引擎UE5】SpawnActor生成Character實例不執行AI Move To,未初始化AIController的原因和解決方法

虛幻引擎版本&#xff1a;5.5.4 問題描述 剛創建的Third Person項目里&#xff0c;定義一個BP_Enemy藍圖&#xff0c;拖拽到場景中產生的實例會追隨玩家&#xff0c;但SpawnActor產生的實例會固定不動。BP_Enemy藍圖具體設計如下&#xff1a; BP_Enemy的Event Graph ?? 又定義…

跨平臺RTSP高性能實時播放器實現思路

跨平臺RTSP高性能實時播放器實現思路 目標&#xff1a;局域網100ms以內超低延遲 一、引言 現有播放器&#xff08;如VLC&#xff09;在RTSP實時播放場景中面臨高延遲&#xff08;通常數秒&#xff09;和資源占用大的問題。本文提出一種跨平臺解決方案&#xff0c;通過網絡層…

HTTP 失敗重試(重發)方案

在 Qt 網絡開發中&#xff0c;使用 QNetworkAccessManager 進行 HTTP 請求時&#xff0c;可能會遇到網絡超時、服務器錯誤等情況。為了提高請求的可靠性&#xff0c;可以實現 HTTP 失敗重試&#xff08;重發&#xff09; 機制。下面介紹幾種常見的 失敗重發方案&#xff1a; 單…

大白話詳細解讀React框架的diffing算法

1. Diffing 算法是什么&#xff1f; Diffing 算法是 React 用來比較虛擬 DOM&#xff08;Virtual DOM&#xff09;樹的一種算法。它的作用是找出前后兩次渲染之間的差異&#xff08;diff&#xff09;&#xff0c;然后只更新這些差異部分&#xff0c;而不是重新渲染整個頁面。 …

【Linux內核系列】:動靜態庫詳解

&#x1f525; 本文專欄&#xff1a;Linux &#x1f338;作者主頁&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客勵志語錄&#xff1a; 有些鳥兒是注定是關不住的&#xff0c;因為它們的每一片羽翼都沾滿了自由的光輝 ★★★ 本文前置知識&#xff1a; 編譯與鏈接的過程…

深度解讀DeepSeek部署使用安全(48頁PPT)(文末有下載方式)

深度解讀DeepSeek&#xff1a;部署、使用與安全 詳細資料請看本解讀文章的最后內容。 引言 DeepSeek作為一款先進的人工智能模型&#xff0c;其部署、使用與安全性是用戶最為關注的三大核心問題。本文將從本地化部署、使用方法與技巧、以及安全性三個方面&#xff0c;對Deep…

【詳細解決】pycharm 終端出現報錯:“Failed : 無法將“Failed”項識別為 cmdlet、函數、腳本文件或可運行程序的名稱。

昨天在終端一頓操作后突然打開pycharm時就開始報錯&#xff1a; 無法將“Failed”項識別為 cmdlet、函數、腳本文件或可運行程序的名稱。請檢查名稱的拼寫&#xff0c;如果包括路徑&#xff0c;請確保路徑正確&#xff0c;然后再試一次。 所在位置 行:1 字符: 1 Failed to act…

【電路筆記】-D型觸發器

D型觸發器 文章目錄 D型觸發器1、概述2、主從D觸發器3、使用D型觸發器進行分頻4、D觸發器作為數據鎖存器5、透明數據鎖存器6、總結D型觸發器是一種改進的置位-復位觸發器,通過增加一個反相器來防止S和R輸入處于相同的邏輯電平。 1、概述 D型觸發器克服了基本SR NAND門雙穩態電…

智慧共享桿:城市智能化管理的 “多面手”

智慧共享桿&#xff1a;城市智能化管理的 “多面手” 在智慧城市建設的進程中&#xff0c;智慧共享桿憑借其多功能與集約化的特性&#xff0c;逐漸成為城市基礎設施建設領域的重點關注對象。它不僅革新了傳統路燈桿的固有模式&#xff0c;更為城市的高效管理與便捷服務開創了全…

【Tips】pip臨時換源

pip換源網站 用法&#xff1a; pip install xxx庫 -i https://pypi.tuna.tsinghua.edu.cn/simple https://pypi.tuna.tsinghua.edu.cn/simplehttps://mirrors.aliyun.com/pypi/simplehttps://pypi.douban.com/simplehttps://pypi.mirrors.ustc.edu.cn/simplehttps://mirrors.…

AcWing 838:堆排序 ← 數組模擬

【題目來源】 https://www.acwing.com/problem/content/840/ 【題目描述】 輸入一個長度為 n 的整數數列&#xff0c;從小到大輸出前 m 小的數。 【輸入格式】 第一行包含整數 n 和 m。 第二行包含 n 個整數&#xff0c;表示整數數列。 【輸出格式】 共一行&#xff0c;包含…

Microchip AN1477中關于LLC數字補償器的疑問

最近在學習Microchip的AN1477關于LLC的功率級傳遞函數推導及數字補償器設計&#xff0c;對其中的2P2Z數字補償器的系數有一些困惑。我在MATLAB中運行了源程序提供的VMC_LLC.m文件&#xff0c;發現有些地方和AN1477中的結果不一致。現在把相關有疑問的地方列舉出來&#xff0c;也…

【原創】使用ElasticSearch存儲向量實現大模型RAG

一、概述 檢索增強生成&#xff08;Retrieval-Augmented Generation&#xff0c;RAG&#xff09;已成為大型語言模型&#xff08;LLM&#xff09;應用的重要架構&#xff0c;通過結合外部知識庫來增強模型的回答能力&#xff0c;特別是在處理專業領域知識、最新信息或企業私有數…

分享下web3j 常見用法

轉賬 fun sendEthTransaction(privateKey: String,toAddress: String,amount: BigDecimal) {//chainIdval chainId:Long 1//url 可以從https://chainlist.org/里面獲取可用節點//eth轉賬&#xff0c;bnb同理&#xff0c;但需發送到bnb對應節點val url "https://xxx"…

《真·滕王閣序》

《滕工閣序》 西二旗故地&#xff0c;后廠新府。 星分百度網易&#xff0c;地接騰訊阿里。 襟PRD而帶OKR&#xff0c;控需求以引撕逼。 物華天寶&#xff0c;龍光射工卡芯片&#xff1b;人杰地靈&#xff0c;徐孺坐產品經理之榻。 工位霧列&#xff0c;碼農星馳。 臺積電…