當進程結束后所有線程都終止。多線程編程最大的問題在於共享數據的訪問控制。
直接用Win32 API進行編程有很多優點:基於Win32的應用程序執行代碼小,運行效率高。但是它要求程序員編寫的代碼較多,且需要管理所有系統提供給程序的資源。
▶ 創建線程
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
SIZE_T dwStackSize, // initial stack size
LPTHREAD_START_ROUTINE lpStartAddress, // thread function
LPVOID lpParameter, // thread argument
DWORD dwCreationFlags, // creation option
LPDWORD lpThreadId // thread identifier
);
線程函數原型:DWORD WINAPI Fun(LPVOID lpParamter);
參數說明:
lpThreadAttributes :NULL使用默認安全性,不可以被子線程繼承,否則需要定義一個結構體將它的bInheritHandle成員初始化為TRUE。
dwStackSize:設置初始棧的大小,以字節為單位,如果為0,那么默認將使用與調用該函數的線程相同的棧空間大小。任何情況下,Windows根據需要動態延長堆棧的大小。
lpStartAddress:指向線程函數的指針,形式:@函數名,函數名稱沒有限制,但是必須以下列形式聲明:DWORD WINAPI ThreadProc (LPVOID lpParam) ,格式不正確將無法調用成功。但lpStartAddress要這樣通過LPTHREAD_START_ROUTINE轉換如:(LPTHREAD_START_ROUTINE)MyVoid。MyVoid聲明為 void MyVoid();
lpParameter:向線程函數傳遞的參數,是一個指向結構的指針,不需傳遞參數時,為NULL。
dwCreationFlags:可取如下標志
1. CREATE_SUSPENDED(0x00000004):創建一個掛起的線程
2. 0:表示創建后立即激活
3. STACK_SIZE_PARAM_IS_A_RESERVATION(0x00010000):dwStackSize參數指定初始的保留堆棧的大小,否則,dwStackSize指定提交的大小。該標記值在Windows 2000/NT and Windows Me/98/95上不支持。
lpThreadId:保存新線程的id。
返回值:
如果CreateThread成功,傳回一個handle,代表新線程。否則傳回一個FALSE。如果失敗,你可以調用GetLastError()獲知原因。
必須指定的參數是lpStartAddress,其它的都可以用默認值0或NULL。
▶ 恢復/掛起線程
DWORD WINAPI ResumeThread( __in HANDLE hThread);
調用該函數可以激活一個掛起的線程。
這個函數和SuspendThread相對應。創建線程是可以創建掛起的線程
(dwCreationFlags參數指定),掛起的線程直到調用ResumeThread才開始執行。
設置線程優先級
BOOL SetThreadPriority(
HANDLE hThread, // handle to the thread
int nPriority // thread priority level
);
nPriority 優先級別參數 可設置為以下參數
THREAD_PRIORITY_ABOVE_NORMAL 為比一般優先級高一個等級
THREAD_PRIORITY_BELOW_NORMAL 比一般低一個等級
THREAD_PRIORITY_HIGHEST 比一般高2個等級
THREAD_PRIORITY_IDLE
THREAD_PRIORITY_LOWEST 比一般低2個等級
THREAD_PRIORITY_NORMAL 一般等級
THREAD_PRIORITY_TIME_CRITICAL
▶ 終止線程
線程內終止
如果某線程調用了ExitThread函數就可以終止它自己。
VOID ExitThread(DWORD dwExitCode);
dwExitCode: 指定線程的推出碼。
線程外終止
BOOL TerminateThread( HANDLE hThread, DWORD dwExitCode);
作用:
在線程外終止一個線程,用於強制終止線程。
參數說明:
HANDLE htread:被終止的線程的句柄,為CWinThread指針。
DWORD dwExitCode:退出碼。
▶ 關閉句柄
在CreateThread成功之后會返回一個hThread的handle,且內核對象的計數加1,CloseHandle之后,引用計數減1,當變為0時,系統刪除內核對象。
但是這個handle並不能完全代表這個線程,它僅僅是線程的一個“標識”,系統和用戶可以利用它對相應的線程進行必要的操縱。如果在線程成功創建后,不再需要用到這個句柄,就可以在創建成功后,線程退出前直接CloseHandle掉,但這並不會影響到線程的運行。
不執行CloseHandle() 帶來的后果:
若在線程執行完之后,沒有通過CloseHandle()將引用計數減1,在進程執行期間,將會造成內核對象的泄露,相當與句柄泄露,但不同於內存泄露, 這勢必會對系統的效率帶來一定程度上的負面影響。但是,請記住,當進程結束退出后,系統仍然會自動幫你清理這些資源。但是在這里不推薦這種做法,畢竟不是 一個良好的編程習慣!
( 應用程序運行時,有可能泄露內核對象,但是當進程終止運行時,系統能確保所有內容均被正確地清除。另外,這個情況是用於所有對象,資源和內存塊,也就是說,當進程終止時,系統將保證不會留下任何對象。)
▶ 判斷程序運行狀態
線程結束代碼可以藉由調用GetExitCodeThread()而得知。
BOOL GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode);
▶ 同步與互斥
Win32 API提供了一組能是線程阻塞自身執行的等待函數。這些等待函數在其參數中的一個或多個同步對象產生了信號,或者超過規定的等待時間才會返回。在等待未返回時,線程處於等待狀態,此時線程只消耗很少的CPU。
最常用的等待函數是:
DWORD WINAPI WaitForSingleObject(
__in HANDLE hHandle,
__in DWORD dwMilliseconds
);
參數:
hHandle: 對象句柄。可以指定一系列的對象,如Event、Job、Memory resource notification、Mutex、Process、Semaphore、Thread、Waitable timer等。
當等待仍在掛起狀態時,句柄被關閉,那么函數行為是未定義的。該句柄必須具有 SYNCHRONIZE 訪問權限。
dwMilliseconds: 定時時間間隔,單位為milliseconds(毫秒).如果指定一個非零值,函數處於等待狀態直到hHandle 標記的對象被觸發,或者時間到了。如果dwMilliseconds 為0,對象沒有被觸發信號,函數不會進入一個等待狀態,它總是立即返回。如果dwMilliseconds 為INFINITE,對象被觸發信號后,函數才會返回。
返回值:
WAIT_ABANDONED 0x00000080:當hHandle為mutex時,如果擁有mutex的線程在結束時沒有釋放核心對象會引發此返回值。
WAIT_OBJECT_ 0 0x00000000 :核心對象已被激活
WAIT_TIMEOUT 0x00000102:等待超時
WAIT_FAILED 0xFFFFFFFF :出現錯誤,可通過GetLastError得到錯誤代碼