C語言多執行緒基礎-01-執行緒的建立與銷燬
一.執行緒建立
首先要關聯標頭檔案Window.h,需要使用Windows系統的底層方法
1.1 執行緒建立演示:
//定義一個方法,彈出一個訊息框
//該方法返回值為DWORD WINAPI型別,引數為一個空指標
DWORD WINAPI run(void * p) {
MessageBox(0, "多執行緒測試", "資訊", 0);
}
//main方法中開啟執行緒
int main(void) {
//使用_beginthread方法開啟執行緒,讓開啟的執行緒執行run方法
_beginthread(run, 0, NULL);
//使用CreateThread方法開啟執行緒,讓開啟的執行緒執行run方法
CreateThread(NULL, 0, run, NULL, 0, NULL);
system("pause");
return 0;
}
執行程式,結果如下,同時彈出兩個訊息框(不使用多執行緒時必須關閉一個訊息框才會彈出下一個)
_beginthread方法和CreateThread各開啟了一個執行緒,兩個執行緒均彈出了一個訊息框
1.2 執行緒建立方法詳解:
1)_beginthread方法
_beginthread方法的定義
uintptr_t _beginthread( // NATIVE CODE
void( __cdecl *start_address )( void * ),
unsigned stack_size,
void *arglist
);
_beginthread方法的引數
引數 | 含義 |
---|---|
start_address | 啟動開始執行新執行緒的例程的地址,是一個指標型別的資料,可以使用函式名做為引數,因為函式名就是一個指標 |
stack_size | 用於設定新開啟的執行緒的執行緒棧的大小(每個執行緒都有一個私有的執行緒棧),如果設定為0,則會按照預設大小建立 |
arglist | 要傳遞到新執行緒的引數列表或 NUL |
2)CreateThread方法
CreateThread方法的定義
HANDLE WINAPI CreateThread(
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_ SIZE_T dwStackSize,
_In_ LPTHREAD_START_ROUTINE lpStartAddress,
_In_opt_ LPVOID lpParameter,
_In_ DWORD dwCreationFlags,
_Out_opt_ LPDWORD lpThreadId
);
CreateThread方法的引數
引數 | 含義 |
---|---|
lpThreadAttributes | 用於設定執行緒安全級別 |
dwStackSize | 用於設定新開啟的執行緒的執行緒棧的大小(每個執行緒都有一個私有的執行緒棧),如果設定為0,則會按照預設大小建立 |
lpStartAddress | 啟動開始執行新執行緒的例程的地址,是一個指標型別的資料,可以使用函式名做為引數,因為函式名就是一個指標 |
dwCreationFlags | 指登錄檔的鍵值,設定為0即可,程式執行時編譯器會根據系統自動查詢登錄檔的鍵值 |
lpThreadId | 執行緒ID |
3)建立執行緒涉及到的方法的返回值
run方法的返回值
建立執行緒的兩個方法中,均有一個引數用來指定新開啟的執行緒要執行的方法,該方法返回一個DWORD WINAPI型別的返回值,根據DWORD WINAPI的定義,可以看出是一個long型別的資料
typedef unsigned long DWORD;
#define APIENTRY WINAPI
DWORD
DWORD全稱Double Word,是指登錄檔的鍵值,每個word為2個位元組的長度,DWORD雙字即為4個位元組
裝置驅動程式和服務的許多引數都是DWORD型別,以二進位制、十六進位制或十進位制格式顯示在登錄檔編輯器中
DWORD根據作業系統的不同,被定義成了不同的長度,比如vs8(xp)中,DWORD被定義成了如下的型別:typedef unsigned long DWORD; 而unsigned long 的長度則是4個位元組即32位,如果是在64位的作業系統中,這個長度可能會更長,取決於當前作業系統以及開發環境
CreateThread方法,和_beginthread方法的返回值:
一個HANDLE型別的資料
HANDLE
上述兩個建立執行緒的方法都返回一個HANDLE WINAPI型別的引數,HANDLE 的中文含義是把手,操縱,專業術語為控制代碼。
HANDLE詳解
HANDLE是Windows作業系統中的一個概念。在Windows程式中,有各種各樣的資源(視窗、圖示、游標等),系統在建立這些資源時會為它們分配記憶體,並返回標示這些資源的標示號,即控制代碼。
控制代碼:
指的是一個核心物件在某一個程序中的唯一索引,而不是指標。由於地址空間的限制,控制代碼所標識的內容對程序是不可見的,只能由作業系統通過程序控制代碼列表來進行維護。
控制代碼列表:
每個程序都要建立一個控制代碼列表,這些控制代碼指向各種系統資源,比如訊號量,執行緒,和檔案等,程序中的所有執行緒都可以訪問這些資源。
二.執行緒銷燬
2.1 執行緒銷燬演示:
void main() {
printf("測試第一種執行緒結束方法");
system("pause");
//_beginthread(endThread_1,0, NULL);
printf("測試第二種執行緒結束方法");
system("pause");
//CreateThread(NULL, 0, endThread_2, NULL, 0, NULL);
printf("測試第三種執行緒結束方法");
system("pause");
HANDLE handle = CreateThread(NULL, 0, endThread_3, NULL, 0, NULL);
Sleep(3000);
//外部退出執行緒的方法,引數為需要被結束的執行緒的HANDLE值
TerminateThread(handle , 0 );
system("pause");
}
DWORD WINAPI endThread_1(void *p) {
int i = 1;
while (1) {
printf("\n%d\n", i);
Sleep(1000);
i++;
if (i == 10) {
//內部退出執行緒的方法,執行緒執行到該語句後結束
_endthread();
}
}
}
DWORD WINAPI endThread_2(void *p) {
int i = 1;
while (1) {
printf("\n%d\n", i);
Sleep(1000);
i++;
if (i == 10) {
//內部退出執行緒的方法,執行緒執行到該語句後結束
ExitThread(0);
}
}
}
DWORD WINAPI endThread_3(void *p) {
int i = 1;
while (1) {
printf("\n%d\n", i);
Sleep(1000);
i++;
}
}
上述程式的執行情況:
前兩種執行緒結束方法,在開始執行後列印數字,當列印到數字10時停止,執行緒結束。第三種方法在開始執行後列印數字,列印到數字3時停止列印
2.2 執行緒銷燬方法詳解:
1)_endthread方法
_endthread方法的定義
void _endthread( void );
2)ExitThread方法
ExitThread方法的定義
VOID WINAPI ExitThread(
_In_ DWORD dwExitCode
);
dwExitCode引數是,執行緒的退出程式碼,輸入0即可
3)TerminateThread方法
TerminateThread方法的定義
BOOL WINAPI TerminateThread(
_Inout_ HANDLE hThread,
_In_ DWORD dwExitCode
);
hThread引數是執行緒的HANDLE值
dwExitCode引數是,執行緒的退出程式碼,輸入0即可