標籤:mon 調用 demo 包含 struct 處理機 ges not 設計者
- 011_線程啟動到死亡的詳細講解
- 1. 線程核心對象
- 使用計數 2 ##決定當前線程何時銷毀
- 暫停計數 1 ##UINT類型初始為1,可以暫停多次,如置為0則取消暫停。
- 結束代碼 STILL_ACTIVE
- Signaled FALSE
- CONTEXT 為空白
- 2. 棧
##在隸屬於當前進程的空間中,分配一塊“棧”空間,以供線程使用
- 3. CONTEXT
##線程上一次運行時的寄存器
- IP(指令寄存器) void RtlUserThreadStart(未公開的函數)(lpParam,lpFnAddr)
- SP(棧寄存器) lpFnAddr
- 4. 交給CPU調度
- 5. RtlUserThreadStart
- SEH ##設定結構化異常
- 調用線程函數,傳遞lpParam
- 等待線程函數的返回
- ExitThread ## 使用計數遞減
- 012_beginthreadex和CreateThread
- 多線程運行庫的設定
- _beginthreadex() 函數隸屬於C標準的運行庫,要包含標頭檔: process.h
- 非安全執行緒:
- 多線程訪問全域變數時,會有出錯的機率。
- 舉例C語言的錯誤處理機制:errno 非安全執行緒
- C語言的設計者,為瞭解決線程的安全問題,給出了_beginthreadex()函數。
- _beginthreadex()函數的區別:
- 1 參數與 CreateThread()函數的參數意義相同,但其類型已經不同。
- 2 beginthreadex()比CreateThread()函數,多開闢了一段空間,分配在堆上面,儲存一些全域的變數。以期安全執行緒。多分配了堆空間後,才來調用CreateThread();
- 3 使用beginthreadex()要配套_endthreadex()使用.
- 建議使用_beginthreadex(),有多分配一段堆空間。
- _beginthread()函數不建議使用,因為其並沒有多分配一段堆空間。這裡要注意使用EX版本的函數。
- 013_線程狀態
- 014_線程的掛起轉態
- 啟動
- CONTEXT 初始
- 使用計數 置為2
- 暫停計數 置為1
- 在後續CreateThread完成後,減1得出0,為0則進入CPU的調度。當前線程是可執行檔狀態。
- 運行
- 執行我們的函數
- 時不時的切換線程,將CPU寄存器的狀態寫入CONTEXT
- 切換到當前時,先讀取CONTEXT
- 掛起
- SuspendThread() 32位 Wow64SuspendThread() 64位
- 調用暫停線程函數SuspendThread(),函數會把暫停計數+1
- SuspendThread函數會返回0,第一次調用結束時返回1;第二次調用時返回1,第二次結束時返回2. 此函數有調用時的返回,與結束時的返回。
- ResumeThread() 恢複掛起線程
- 調用此函數,會把當前線程的暫停計數-1
- 有幾次掛起,就要有幾次恢複調用,不然線程仍然不會進入運行。
- 不建議使用線程的掛起:
- 如果線程入口函數裡面,有new新的堆空間,而作業系統切換線程時,有可能會使得這塊堆空間,在被佔用的情況下,卻沒有佔用的標記。此時當此堆空間被訪問時,就出了非常隱形BUG。
- 要區分2種掛起:
- 1 作業系統切換線程時的“掛起”——在“池”中
- 準確來說是“切換”線程。按作業系統的演算法,線程在進行CPU調度時,所產生的暫停。
- 2 SuspendThread()函數產生的掛起 ——不在“池”中
- 015_線程 等待、休眠、及饑餓線程
- 等待休眠 Sleep()
- Sleep(100); 表示休眠100毫秒後,CPU再來運行;
- 這裡100毫秒並不能準確不差,因為windows作業系統非即時的,CPU的運行時調度也是非即時的;所以在時間方面有一點誤差,只能說是無限接近100毫秒。
- 放棄當前的時間片,在一段時間之內,CPU不會調度此線程
- Sleep(INFINITE) 永遠等待
- INFINITE 其值為-1;
- 一直等待到進程結束
- Sleep(0) 放棄線程執行時間片
- SwitchToThread() 把CPU剩餘的時間片,分配給"饑餓度"較高的線程.
- 調度另外一個線程,也就是把CPU的執行循環給另外一個線程身上。
- CPU時間片“饑餓度”:如果一此線程相對時間片很少,或者一直沒有得到執行,我們就稱其為“饑餓”線程。饑餓度相對較高。
- 016_CONTEXT結構體
- 源碼
typedef struct _CONTEXT { // // The flags values within this flag control the contents of // a CONTEXT record. // // If the context record is used as an input parameter, then // for each portion of the context record controlled by a flag // whose value is set, it is assumed that that portion of the // context record contains valid context. If the context record // is being used to modify a threads context, then only that // portion of the threads context will be modified. // // If the context record is used as an IN OUT parameter to capture // the context of a thread, then only those portions of the thread‘s // context corresponding to set flags will be returned. // // The context record is never used as an OUT only parameter. // DWORD ContextFlags; // // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT // included in CONTEXT_FULL. // DWORD Dr0; DWORD Dr1; DWORD Dr2; DWORD Dr3; DWORD Dr6; DWORD Dr7; // // This section is specified/returned if the // ContextFlags word contians the flag CONTEXT_FLOATING_POINT. // FLOATING_SAVE_AREA FloatSave; // // This section is specified/returned if the // ContextFlags word contians the flag CONTEXT_SEGMENTS. // DWORD SegGs; DWORD SegFs; DWORD SegEs; DWORD SegDs; // // This section is specified/returned if the // ContextFlags word contians the flag CONTEXT_INTEGER. // DWORD Edi; DWORD Esi; DWORD Ebx; DWORD Edx; DWORD Ecx; DWORD Eax; // // This section is specified/returned if the // ContextFlags word contians the flag CONTEXT_CONTROL. // DWORD Ebp; DWORD Eip; DWORD SegCs; // MUST BE SANITIZED DWORD EFlags; // MUST BE SANITIZED DWORD Esp; DWORD SegSs; // // This section is specified/returned if the ContextFlags word // contains the flag CONTEXT_EXTENDED_REGISTERS. // The format and contexts are processor specific // BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];} CONTEXT;
- 017_安全執行緒及上鎖
- 樣本
// ContextDemo.cpp : 定義控制台應用程式的進入點。//#include "stdafx.h"#include <windows.h>#include <process.h>BOOL bUseing = FALSE;unsigned int __stdcall ThreadRun(void* lParam){int nNum = 0;while (true){if (!bUseing){bUseing = TRUE;_tprintf(TEXT("ThreadRun:%d\r\n"), nNum++);bUseing = FALSE;}}}unsigned int __stdcall ThreadMonitor(void* lParam){HANDLE hThread = (HANDLE)(lParam);while (true){CONTEXT context;context.ContextFlags = CONTEXT_ALL;SuspendThread(hThread);GetThreadContext(hThread, &context);if (!bUseing){bUseing = TRUE;_tprintf(TEXT("EAX:0x%x ESP:0x%x EIP:0x%x\r\n"), context.Eax, context.Esp, context.Eip);bUseing = FALSE;}ResumeThread(hThread);}}int main(){HANDLE hThreads[2];hThreads[0] = (HANDLE)_beginthreadex(nullptr, 0, ThreadRun,nullptr, 0, nullptr);hThreads[1] = (HANDLE)_beginthreadex(nullptr, 0, ThreadMonitor,hThreads[0], 0, nullptr);WaitForMultipleObjects(sizeof(hThreads)/sizeof(HANDLE),hThreads,true,INFINITE);for (int i = 0; i<sizeof(hThreads)/sizeof(HANDLE);++i){CloseHandle(hThreads[i]);} return 0;}
PoEdu - Windows階段班 【Po學校】Lesson006_線程_線程的啟動到消亡 &線程狀態 & 安全執行緒 & CONTEXT結構體 & 令牌鎖