多執行緒技術——windows.h【1】
執行緒的狀態
執行緒有掛起狀態、執行狀態、阻塞狀態和等待狀態。
下面分別介紹:
- 掛起狀態:執行緒建立後並沒有直接執行或是呼叫函式掛起了執行緒。被掛起了的執行緒沒有執行的能力,只有呼叫啟動函數了之後才能執行。
- 執行狀態:線上程的時間片內,擁有CPU資源的時候,這是,執行緒便開始執行。
- 阻塞狀態:由於進行大量輸入輸出操作或發生執行錯誤時,執行緒失去執行狀態,只有等待問題解除之後,執行緒才能進入等待狀態。
- 等待狀態:執行緒啟動或時間片搶佔失敗是等待其他執行緒執行,在此期間,執行緒隨時可能被執行。
多執行緒實現
執行緒核心物件就是一個包含了執行緒狀態資訊的資料結構。每次對CreateThread 的成功呼叫,系統都會在內部為其分配一個核心物件。
執行緒上下文反應了執行緒上次執行的暫存器狀態,來保證執行緒之間切換(即還原現場)。
計數器,呼叫一次OpenThread(CreateThread ),計數器加1,CloseThread(CloseHandle)計數器減一。當計數器值為0時,沒有執行緒使用該核心物件,系統收回記憶體。計數器的初始值是2(主執行緒是1,建立的執行緒是2)。
- 標頭檔案 因為C++不像Java一樣需要進行跨平臺優化,所以我們使用最簡單的方法來實現多執行緒技術——windows.h中的CreateThread以及相關函式和類。首先,以如下的方式引用標頭檔案:
#include<windows.h>
- 函式原型:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, //執行緒安全性描述(一個結構體,一般是NULL)
SIZE_T dwStackSize, //一種數值(棧深度,一般是0)
LPTHREAD_START_ROUTINE lpStartAddress, //啟動函式
_In_opt_ __drv_aliasesMem LPVOID lpParameter, // 附加引數(一般為NULL)
_In_ DWORD dwCreationFlags, //執行引數(是否在建立完成後就啟動執行緒
_Out_opt_ LPDWORD lpThreadId // 返回控制代碼(一般是0,或者是一個DWORD型變數的地址,別忘了&)
);
-
引數說明 第三個引數 ——啟動函式:
c LPTHREAD_START_ROUTINE lpStartAddress
我們一般這樣寫: (LPTHREAD_START_ROUTINE) ThreadStart 意思就是線上程啟動的時候呼叫ThreadStart,之後他就不管了,也就是說這個函式? 就是執行緒主函式相當於main的意思。也就是說在這個函式中呼叫的類資源或函式資源 都是屬於這個執行緒的。除了static的儲存類。
倒數第二個引數——執行引數。
這是實際上是一個bool型別的值,用於標示是否在建立執行緒後立刻執行,如果為true,也就是0,那麼就會立刻執行,否則將會掛起,等待啟動
-
返回值 還有我要說一下HANDLE這個型別,它其實是一個指標,也是CreateThread的返回值。也就是一個執行緒控制代碼,用於標示一個執行緒。當然,其他對於執行緒的操作都需要使用這個指標。
-
啟動執行緒: 如果呼叫這個函式,將會啟動HANDLE引數所代表的執行緒.
DWORD ResumeThread(HANDLE hThread); //啟動執行緒 //說明:DWORD是一個數值,代表控制代碼,無需關注; //引數表示要啟動的執行緒的控制代碼,也就是剛才介紹的由CreateThread返回的HANDLE
-
掛起執行緒 下面我們看看如何掛起執行緒,使執行緒進入掛起狀態:
DWORD SuspendThread(HANDLE hThread); //掛起執行緒 //說明:DWORD是一個整數值,代表一個控制代碼,無需過分關注 //引數:一個HANDLE執行緒指標,由CreateThread建立
-
停止執行緒 掛起執行緒後可以進行釋放以便停止執行緒:
delete HANDLE //釋放指標資源 //說明:HANDLE是一個HANDLE型指標,代表釋放一個執行緒的資源,使執行緒死亡
實際上,停止一個執行緒還有一種方法——強行停止,但是已經不建議使用,現在都是使用掛起+delete的方法,因為使用強行停止會有很多的安全問題,但也是一個功能,所以在這裡為大家介紹一下:
BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode); //強行停止執行緒 //說明:返回值代表是否成功 //引數:HANDLE指標代表需要結束的執行緒,DWORD數值代表該執行緒的退出值 //功能:在任何位置結束任何執行緒
-
等待狀態 掛起執行緒可能為了等待重要操作然後再執行執行緒,以下函式將解除執行緒掛起狀態,使執行緒進入等待狀態:
DWORD ResumeThread(HANDLE hThread); //使執行緒脫離掛起狀態 //說明:返回值也是控制代碼 //引數:HANDLE型別指標,表示要繼續的執行緒,或剛建立而沒有啟動的執行緒 //注意:如果對等待狀態下的執行緒使用本函式,可能會丟擲異常或無效果,具體請見MSDN
-
簡單的例程
//多執行緒搶佔輸出 #include <iostream> #include <windows.h> using namespace std; void ThreadUser() { //執行緒入口 cout << "子執行緒開始" << endl; for (int i = 0; i < 10; i++) { //搶佔迴圈 cout << "子執行緒第" << i << "次迴圈搶佔;" << endl; //輸出資訊 Sleep(100); //搶佔延時 } cout << "子執行緒結束" << endl; } int main() { cout << "主執行緒開始" << endl; HANDLE h; //執行緒控制代碼 h=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadUser, NULL, 1, 0); //建立子執行緒 ResumeThread(h); //啟動子執行緒 for (int i = 0; i < 10; i++) { //搶佔迴圈 cout << "主執行緒第" << i << "次迴圈搶佔;" << endl; //輸出資訊 Sleep(100); //搶佔延時 } Sleep(1000); //等待子執行緒 CloseHandle(h); cout << "主執行緒結束" << endl; system("pause"); return 0; }