線程核心對象每個進程裡,都有一個線程,作業系統用線程核心對象來管理線程。線程有2部分組成:1 線程核心對象。 作業系統來管理線程 2 線程棧, 來存在函數和局部變數的地址空間。什麼情況下使用多線程? 當各個任務彼此獨立時,可以使用多線程,如:開一個後台線程來檢測文法。什麼情況下不要使用多線程? 任務聯絡緊密。如 掃描一個目錄的檔案,就不適合開多個線程處理,這樣處理起來複雜度很高!實現CreateThread 來建立一個線程.如果是C、C++代碼的話,使用_beginThreadEx來建立線程為什嗎? 因為有些C函數裡面使用了靜態變數,那麼多個線程執行的話,會有衝突,但是_beginThreadex做了線程局部處理,它內部就調用了CreateThread函數。WINBASEAPI 表示是winbase.h的API
__out_opt 表示是輸出
HANDLE
WINAPI
CreateThread(
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, 安全屬性,一般為NULL表示預設
__in SIZE_T dwStackSize, 線程棧的空間,一般使用0來表示預設值
__in LPTHREAD_START_ROUTINE lpStartAddress, 線程函數地址
__in_opt LPVOID lpParameter, 線程函數參數
__in DWORD dwCreationFlags, 建立線程時,指定啥標誌 0 表示立即開始執行,CREATE_SUSPENDED 表示暫停
__out_opt LPDWORD lpThreadId 返回線程ID,不需要時,可以傳遞NULL,表示不關心
);終止運行線程的4種方式:1 線程函數返回(推薦)可以清理C++對象資源,會調用C++的解構函式清理線程棧2 自己調用ExitThread(避免使用)不會調用C++的解構函式清理線程棧如果使用的是C++代碼,那麼調用_endThreadEx() 來替換ExitThread3 其它線程調用TerminateThread() 避免使用不會調用C++解構函式,也不會清理線程棧ExitThread來結束的線程,會清理堆棧,但是調用terminateThread()函數 不會清理堆棧資訊,除非線程所在進程終止。4 線程所在的進程終止 避免使用C++解構函式不會調用,線程被強行殺死,正常的清理工作沒有執行。線程終止時,會發生以下事情:1 線程擁有的所有物件控點被釋放一個線程有2個使用者物件: 視窗和掛鈎2 退出碼有STILL_ACTIVE 變成 ExitThread 或者TerminateThread 返回的退出碼3 線程核心對象變成觸發狀態4 如果線程是最後一個活動線程,那麼進程也終止。5 線程核心對象的引用計數減一C和C++庫標準的C和C++庫,最開始不是為了多線程設計的,在多線程環境下有些函數會出問題:errno,_doserrno, strtok, _wcstok, strerror, _strerror, tmpnam, tmpfile,asctime,gmtime,等所以要不要調用系統的CreateThread,而要調用C,C++運行庫 _beginthreadex_beginthreadex 分配和初始化 初始化資料區塊,並將它與新的線程關聯起來_endthreadex 函數 線上程終止啟動並執行 釋放分配的資料區塊不要使用C和C++運行庫的這一對函數_beginthread ,
_endthread瞭解自己的身份返回當前進程的控制代碼 和 IDHANDLE GetCurrentProcess();DWORD GetCurentProceddID();返回當前線程的控制代碼 和 IDHANDLE GetCurrentThread();DWORD GetCureentThreadID();注意: 上面這2個函數返回的都是偽控制代碼偽控制代碼:表示當前線程的控制代碼,即調用線程的控制代碼。下面舉一個樣本來分析
#include <iostream>#include <vector>#include <map>#include <Windows.h>#include <tchar.h>#include <process.h>#include <Strsafe.h>HANDLE ghthreadCurrent = NULL;unsigned int WINAPI ThreadFunc2(LPVOID lp);unsigned int WINAPI ThreadFunc1(LPVOID lp){HANDLE hThread = GetCurrentThread();ghthreadCurrent =(HANDLE) _beginthreadex(NULL, 0, ThreadFunc2, hThread, 0, NULL);while(1){printf("111\n");Sleep(1000);}return 0;}unsigned int WINAPI ThreadFunc2(LPVOID lp){HANDLE hThread = (HANDLE)lp;TerminateThread(hThread,0);return 0;}int main(){HANDLE hThread1 =(HANDLE) _beginthreadex(NULL, 0, ThreadFunc1, NULL, 0, NULL );WaitForSingleObject(hThread1,INFINITE);return 0;}
線程2 的線程函數 TerminateThread 會把自己殺死,不會殺死線程1使用一個複製控制代碼的函數 DuplicateHandle() 來複製控制代碼
#include <iostream>#include <vector>#include <map>#include <Windows.h>#include <tchar.h>#include <process.h>#include <Strsafe.h>unsigned int WINAPI ThreadFunc2(LPVOID lp);unsigned int WINAPI ThreadFunc1(LPVOID lp){HANDLE hThread = GetCurrentThread();HANDLE hTagrealThread = NULL;BOOL bOk = DuplicateHandle(GetCurrentProcess(),hThread,GetCurrentProcess(),&hTagrealThread,0,FALSE,DUPLICATE_SAME_ACCESS);(HANDLE) _beginthreadex(NULL, 0, ThreadFunc2, hTagrealThread, 0, NULL);while(1){printf("111\n");Sleep(1000);}return 0;}unsigned int WINAPI ThreadFunc2(LPVOID lp){HANDLE hThread = (HANDLE)lp;Sleep(5000);TerminateThread(hThread,0);//必須要關閉控制代碼CloseHandle(hThread);return 0;}int main(){HANDLE hThread1 =(HANDLE) _beginthreadex(NULL, 0, ThreadFunc1, NULL, 0, NULL );WaitForSingleObject(hThread1,INFINITE);CloseHandle(hThread1);printf("main exit\n");system("pause");return 0;}
線程2函數,殺死的是線程1 最後要關閉線程1的線程核心對象
複製一個控制代碼後,線程核心對象引用計數會加1