1. 程式人生 > >C語言多執行緒基礎-01-執行緒的建立與銷燬

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即可