程式執行緒排程方式
【原文:http://blog.chinaunix.net/uid-20476365-id-1942505.html】
1.程式終止的方式:
(1) 主執行緒的入口函式返回(推薦方式);
(2) 程式主動退出:一個執行緒呼叫ExitProcess;
(3) 程式被動終止:另一個程式呼叫了TerminateProcess;例如通過工作管理員中結束程式。
(4) 程式中的所有執行緒都終止了。
2. 執行緒:
(1) 建立於一個程式的上下文中,在程式的地址空間中執行;
(2) 執行緒是動態的,一個程式至少要有一個執行緒;
(3) 程式中的所有執行緒共享程式的地址空間;
2.1 執行緒的組成部分:
(1) 一個核心態的物件,作業系統用來儲存執行緒的資訊;
(2) 執行緒堆疊,用來存放執行緒執行時的函式引數和區域性變數等。
2.2 執行緒的執行:
(1) 當一個程式初始化時,系統會建立這個程式的主執行緒;
(2) 這個執行緒最初執行C/C++執行時間庫的啟動程式碼,這些啟動程式碼會呼叫程式的入口函式(main,wmain,WinMain,wWinMain);
(3) GUI程式有一個主UI執行緒,處理訊息迴圈和使用者互動。如果這個執行緒被掛起或忙於處理任務,應用程式會失去相應;
(4) 工作執行緒沒有介面,在後臺工作,例如分析資料、資料庫操作等。
2.3 執行緒的終止:
(1) 執行緒函式返回(推薦方式);
(2) 執行緒呼叫ExitThread;
(3) 其他執行緒(可以是其他程式中的執行緒)呼叫TerminateThread;
(4) 該執行緒所在的程式被終止。
2.4 執行緒排程:下面的事件會觸發作業系統的執行緒排程(執行緒排程時,OS會執行上下文切換Context Switch,把執行權從當前執行緒轉移到下一個執行緒):
(1) 一個執行緒進入ready狀態,例如這個執行緒被建立或這個執行緒從等待狀態釋放;
(2) 一個執行緒離開執行狀態,例如這個執行緒的時間片結束了,或終止,或放棄執行(sleep),或進入等待狀態;
(3) 一個執行緒的優先順序改變;
(4) 一個執行緒的processor affinity改變。
2.5 Context Switch:
(1) 儲存當前執行緒的上下文(Context);
(2) 把當前執行緒放在同一優先順序的執行緒佇列的尾部;
(3) 找到最高優先順序的ready執行緒;
(4) 把這個執行緒從它所在的執行緒中移出,裝載它的上下文(Context),開始執行這個執行緒。
2.6 執行緒上下文的內容:
(1) Instruction pointer,記錄執行緒在被掛起前執行到的位置;
(2) 使用者和核心態堆疊指標;
(3) 指向這個執行緒所在的地址空間的指標(Page table diroctory)(e.g:當從程式A中的執行緒B切換到程式C中的執行緒D執行時,需要儲存該值)。
2.7 執行緒的優先順序:
Windows使用32個優先順序別,從0到31,數值越大優先順序越高。
(1) 程式priority class:Real-time,High,Above Normal,Normal,Below Normal,Idle;
(2) 執行緒relative thread priority:Time-critical,Highest,Above normal,Highest,Above normal,Normal,Below normal,Lowest,Idle;實際執行時,執行緒的優先順序是由所屬程式的prioriy class(參考級別)和relative thread priority(偏移級別)兩者結合起來來計算的,
(3) 一個系統級別(0),保留給zero page thread;
2.8 執行緒同步(下面的情況需要做執行緒同步):
(1) 多個執行緒訪問共享資源,在一個時間只有一個執行緒可以訪問共享資源;否則,可能出現的問題是應用程式崩潰;多CPU的情況下尤其要注意這一點;
(2) 一個執行緒需要通知另一個執行緒一項工作已經完成。
3 程式的虛擬地址空間:
在32位第系統上,程式的虛擬地址空間是4G;預設情況下,使用者態和核心態虛擬地址空間各佔2GB;各個程式的使用者態地址空間是相互獨立的,如下圖所示:
3.1 調節使用者態空間大小:
(1) Boot.ini的/3GB選項可以用來調節使用者態虛擬地址空間的大小,把使用者態的地址空間增加到3GB(Win2k,WinXP,Win2k3);
(2) Boot.ini的/USERVA可以指定使用者態地址空間為2GB和3GB之間的一個值(WinXP,Win2K3);
(3) 應用程式的二進位制檔案頭上要有/LARGEADDRESSAWARE標誌,才能訪問高於2GB的地址空間,否則將不能訪問。
3.2 使用者態虛擬地址空間的狀態:
(1) Free:這段地址自由,可被分配;
(2) Reserving:這段地址被預留,不會在分配做他用,沒有影射實體記憶體,不能訪問,只有被Commit之後再可以使用;
(3) Commintted:被影射到實體記憶體。
3.3 程式使用的記憶體:
(1) Private Bytes:程式的虛擬地址空間中已分配的記憶體(包括實體記憶體和虛擬記憶體Paging File中使用的記憶體的綜合),不包括核其他程式共享的記憶體(e.g:二進位制檔案dll和exe檔案的程式碼);
(2) Virtual Bytes:程式所使用的虛擬地址空間的大小,包括核其他程式共享的記憶體,例如共享動態連結庫;
(3) Working Set:程式所使用的實體記憶體的大小,包括核其他程式共享的記憶體。
3.4 記憶體對映檔案:
(1) 程式保留一段虛擬地址空間,把一個檔案中的一部分對映到這段地址空間;可以用這種方式來處理大檔案(size>4GB),使用記憶體對映檔案來處理大檔案,每次只把一部分檔案內容對映到程式的地址空間;
(2) 作業系統使用記憶體對映檔案來裝載.exe和.dll檔案;如果多個程式使用同一個dll檔案,實體記憶體裡只有一份拷貝;多個程式之間共享記憶體:多個程式對映到同一個檔案的用一部分。
3.5 實體記憶體和虛擬記憶體(paging file):
(1) paging file用來儲存程式正在使用的修改過的記憶體,例如當系統實體記憶體不足時或者這部分記憶體在很長一段時間內沒有被使用;
(2) 當這部分內容被訪問時,這些內容再被從paging file轉移到實體記憶體(缺頁處理過程)。
3.6 缺頁處理(page fault):
(1) 被訪問的頁面不在實體記憶體內,但是在硬碟檔案裡或paging file裡或記憶體對映檔案裡;
(2) 作業系統分配實體記憶體,把所需的訪問的內容從硬碟檔案或paging file或記憶體對映檔案裡讀到實體記憶體裡;
(3) 這個過程對應用程式時透明的。
3.7 記憶體訪問流程圖:
3.8 執行緒堆疊(stack):
堆疊是執行緒執行時用來儲存函式引數、區域性變數、函式返回地址等資料的一塊記憶體;系統給每個執行緒reserve一塊使用者態執行緒堆疊,並commit其中的一部分記憶體。預設情況下,reserve 1MB堆疊,並commit其中的2個page(2*4KB),如下圖所示(叢高地址向低地址方向寫):
3.9 堆(Heap):
分配小塊的記憶體;程式的預設堆(1MB);建立更多的堆(HeapCreate、HeapAlloc、HeapReAlloc);
3.10 程式使用記憶體的型別總結:
(1) 虛擬檔案:用於儲存大塊的陣列和資料結構;
(2) 記憶體對映檔案:用於對映可執行檔案、大檔案或多程式之間共享記憶體;
(3) 堆:主要用於大量的小塊記憶體,程式申請記憶體一般是從堆中分配,程式使用的記憶體大部分來自堆,堆實際上是作業系統的堆管理器從虛擬記憶體中分配的;
(4) 堆疊:堆疊儲存執行緒執行時的一些變數、暫存器資訊等,堆疊的空間有限,如果一個執行緒的堆疊用完而且不能再增長,應用程式會崩潰。
4 動態連結庫(DLL):
(1) DLL裡的內容:函式、資料結構、資源等;
(2) DLL不能直接執行,必須被裝載到一個程式中才能執行;
(3) DLL的image被對映到程式的地址空間,然後程式中的所有執行緒可以呼叫DLL中的函式。
4.1 DLL的入口函式:
一個DLL可以指定一個入口函式(DllMain),系統在特定情況下會呼叫DLL的入口函式;下面的情況下系統呼叫DLL的入口函式:
(1) 程式裝載DLL(DLL_PROCESS_ATTACH);
(2) 程式解除安裝DLL(DLL_PROCESS_DETACH);
(3) DLL被裝載之後建立一個新執行緒(DLL_THREAD_ATTACH);
(4) DLL被裝在之後一個執行緒終止(DLL_THREAD_DETACH);
4.2 Load-time dynamic linking:
(1) 編譯器把可執行檔案所需的DLL的名字放在可執行檔案頭的Import部分中;
(2) 可執行檔案開始執行時作業系統檢測可執行檔案頭的Import部分,然後定位和裝載所需的Dll。
(3) 如果作業系統不能找到合適的DLL,會給出一個錯誤訊息對話方塊;
4.3 Run-time dymnamic linking:
(1) 應用程式執行之後呼叫LoadLibrary或LoadLibraryEx裝載DLL,作業系統定位並裝載DLL;
(2) 如果不能找到DLL或DLL入口函式,則返回false,LoadLibrary或LoadLibrary失敗;
(3) 用GetProcAddress獲得DLL的輸出函式地址,並使用這些函式。
4.4 DLL的搜尋順序:
登錄檔鍵:HKLM\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode決定DLL的搜尋順序(Windows Vista、Win2K3、WinXP+SP2中,該鍵值為1;在WinXP和Win2K+SP4 中,該鍵值為0):
(1) SafeDllSearchMode=1
->可執行檔案所在的目錄;
->系統目錄,%SystemRoot%system32;
->16位系統目錄;
->Windows目錄,%SystemRoot%
->程式的當前目錄;
->環境變數Path中的目錄;
(2) SafeDllSearchMode=0或Legacy Search Order:
->可執行檔案所在的目錄;
->程式的當前目錄;
->系統目錄,%SystemRoot%system32;
->16位系統目錄;
->Windows目錄,%SystemRoot%
->環境變數Path中的目錄;
4.5 Known DLLs
Known DLLS是保證用LoadLibrary裝載系統DLL時只從特定的系統目錄裝載,防止裝載錯誤的系統DLL。Known DLLs列表儲存在登錄檔HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager\KnownDLLs鍵值中;作業系統在裝載一個DLL時會檢查KnownDLLs登錄檔下是否有一樣的登錄檔鍵名,如果是,則裝載%SystemRoot%\System32目錄下對應登錄檔鍵值的DLL。
4.6 DLL Hook:
(1) 應用程式註冊hook過程,用於監視一些特定的事件,例如鍵盤按鍵、滑鼠移動、視窗啟用、最小化、最大化、對話方塊裡的輸入等;
(2) Hook DLL被裝載到其他程式裡,一旦遇到上述事件,Hook DLL會執行相應的Hook過程;
(3) 一些惡意軟體會用這種方法竊取使用者輸入的使用者名稱和密碼。
5 異常處理:
應用程式執行時可能遇到異常,如果應用程式沒有處理這些異常,應用程式可能崩潰;常見的異常有訪問非法記憶體地址、執行緒堆疊溢位、遇到斷點(程式裡寫有斷點)、執行非法指令(執行緒堆疊被破壞)等。
5.1 未處理異常:
如果執行緒遇到一個未處理異常,Windows unhandled exception filter會被呼叫;讀取HKLM\Software\Microsoft\WindowsNT\CurrentVersion\AeDebug下的登錄檔鍵值Auto和Debugger(如果Auto為1,則自動執行Debugger指定的除錯程式;預設的Debugger是drwtsn32,生成dump檔案);
如果發生未處理異常,以及Auto是0和Debugger包含"Drwtsn32",系統會檢查HKLM\Software\Microsoft\PCHealth\ErrorReporing決定是否顯示報告錯誤對話方塊。
相關文章
- 多執行緒------執行緒與程式/執行緒排程/建立執行緒執行緒
- Java執行緒的排程Java執行緒
- 程序中的執行緒排程執行緒
- Java併發和多執行緒3:執行緒排程和有條件取消排程Java執行緒
- 多執行緒,執行緒類三種方式,執行緒排程,執行緒同步,死鎖,執行緒間的通訊,阻塞佇列,wait和sleep區別?執行緒佇列AI
- 多執行緒脫離狀態 + 排程執行緒
- RxJava 和 RxAndroid 五(執行緒排程)RxJavaAndroid執行緒
- OpenMP 中的執行緒任務排程執行緒
- 多執行緒-執行緒排程及獲取和設定執行緒優先順序執行緒
- Spring 非同步執行緒池、排程任務執行緒池配置Spring非同步執行緒
- 執行緒、程式與協程執行緒
- 協程、執行緒與程式執行緒
- Golang原始碼學習:排程邏輯(三)工作執行緒的執行流程與排程迴圈Golang原始碼執行緒
- Nachos實驗實現執行緒id、限制執行緒數和更改排程演算法(按優先順序排程)執行緒演算法
- Java排程執行緒池ScheduledThreadPoolExecutor原始碼分析Java執行緒thread原始碼
- RxJava原始碼解析(二)—執行緒排程器SchedulerRxJava原始碼執行緒
- Python——程式、執行緒、協程、多程式、多執行緒(個人向)Python執行緒
- libgo原始碼分析之多執行緒協程管理和排程Go原始碼執行緒
- 程式執行緒協程關係執行緒
- 執行緒 、程式、協程的基本使用執行緒
- 程式、執行緒和協程的概念執行緒
- 多執行緒-匿名內部類的方式實現多執行緒程式執行緒
- 執行緒池建立執行緒的過程執行緒
- JavaEE進階知識學習----多執行緒JUC高階知識-5-執行緒池-Callable-執行緒排程Java執行緒
- NPTL 執行緒同步方式執行緒
- 程式,核心執行緒,使用者執行緒,協程,纖程......作業系統世界觀執行緒作業系統
- 剖析Android中程式與執行緒排程之niceAndroid執行緒
- 執行緒、開啟執行緒的兩種方式、執行緒下的Join方法、守護執行緒執行緒
- 什麼是程式、執行緒和協程?執行緒
- 目前對程式、執行緒、協程的理解執行緒
- Python之執行緒、程式和協程Python執行緒
- Python程式、執行緒、協程詳解Python執行緒
- 程式執行緒篇——程式執行緒基礎執行緒
- 重走JAVA之路(六):你應該要知道的執行緒排程Java執行緒
- jdk排程任務執行緒池ScheduledThreadPoolExecutor工作原理解析JDK執行緒thread
- Linux排程策略及執行緒優先順序設定Linux執行緒
- 多執行緒-多執行緒方式1的程式碼實現執行緒
- boost中asio網路庫多執行緒併發處理實現,以及asio在多執行緒模型中執行緒的排程情況和執行緒安全。執行緒模型