隨着計算機CPU計算能力快速提高,計算機的處理性能和並行性能力也大大提升。那么,一味使用運行時標准庫的C++語言也應該開始支持多線程技術。今天,我為大家帶來了C++在windows平台下的常用多線程方法。
首先我先說一下線程的狀態。線程有掛起狀態、執行狀態、阻塞狀態和等待狀態,下面分別介紹:掛起狀態是說線程創建后並沒有直接執行或是調用函數掛起了線程。被掛起了的線程沒有執行的能力,只有調用啟動函數了之后才能執行。而執行狀態是指在線程的時間片內,擁有CPU資源的時候,這是,線程便開始執行。阻塞狀態是由於進行大量輸入輸出操作或發生執行錯誤時,線程失去執行狀態,只有等待問題解除之后,線程才能進入等待狀態。等待狀態是指線程啟動或時間片搶占失敗是等待其他線程執行,在此期間,線程隨時可能被執行。那么,請大家看一個流程圖:
因為C++不像Java一樣需要進行跨平台優化,所以我們使用最簡單的方法來實現多線程技術——windows.h中的CreateThread以及相關函數和類。首先,以如下的方式引用頭文件:
#include <windows.h>
下面,我們來介紹如何創建線程,我不會向一般的教程那樣上來先羅列一大堆MSDN上的函數原型,把大家弄得糊里糊塗了再講,我首先先把函數原型翻譯成中文好了:
線程句柄 CreateThread(
線程安全性描述(一個結構體,一般是NULL)LPSECURITY_ATTRIBUTES lpThreadAttributes,
一種數值(棧深度,一般是0)DWORD dwStackSize,
啟動函數(一般情況如下闡述) LPTHREAD_START_ROUTINE lpStartAddress,
附加參數(一般為NULL) LPVOID lpParameter,
運行參數(是否在創建完成后就啟動線程,具體下面將)DWORD dwCreationFlags,
返回句柄(一般是0,或者是一個DWORD型變量的地址,別忘了&)LPDWORD lpThreadId);
下面我就重點說一下:
//這第三個參數啟動函數很重要: LPTHREAD_START_ROUTINE lpStartAddress //我們一般這樣寫: (LPTHREAD_START_ROUTINE) ThreadStart //意思就是在線程啟動的時候調用ThreadStart,之后他就不管了,也就是說這個函數就是線程主函數相當於main的意思。也就是說在這個函數中調用的類資源或函數資源都是屬於這個線程的。除了static的存儲類
還有我要說一下HANDLE這個類型,它其實是一個指針,也是CreateThread的返回值。也就是一個線程句柄,用於標示一個線程。當然,其他對於線程的操作都需要使用這個指針。如果你沒有學過指針引用,還是好好復習一下*和&吧。對了還有->。我為什么要介紹HANDLE呢?因為我將要說一下倒數第二個參數——運行參數。這是實際上是一個bool類型的值,用於標示是否在創建線程后立刻執行,如果為true,也就是0,那么就會立刻執行,否則將會掛起,等待啟動。那么,我們用以下方法啟動線程:
DWORD ResumeThread(HANDLE hThread); //啟動線程 //說明:DWORD是一個數值,代表句柄,無需關注; //參數表示要啟動的線程的句柄,也就是剛才介紹的由CreateThread返回的HANDLE
如果調用這個函數,將會啟動HANDLE參數所代表的線程。下面我們看看如何掛起線程,使線程進入掛起狀態:
DWORD SuspendThread(HANDLE hThread); //掛起線程 //說明:DWORD是一個整數值,代表一個句柄,無需過分關注 //參數:一個HANDLE線程指針,由CreateThread創建 //功能:掛起線程直到使用ResumeThread
掛起線程后可以進行釋放以便停止線程:
delete HANDLE //釋放指針資源 //說明:HANDLE是一個HANDLE型指針,代表釋放一個線程的資源,使線程死亡
掛起線程也可能為了等待重要操作然后再執行線程,以下函數將解除線程掛起狀態,使線程進入等待狀態:
DWORD ResumeThread(HANDLE hThread); //使線程脫離掛起狀態 //說明:返回值也是句柄 //參數:HANDLE類型指針,表示要繼續的線程,或剛創建而沒有啟動的線程 //注意:如果對等待狀態下的線程使用本函數,可能會拋出異常或無效果,具體請見MSDN
實際上,停止一個線程還有一種方法——強行停止,但是已經不建議使用,現在都是使用掛起+delete的方法,因為使用強行停止會有很多的安全問題,但也是一個功能,所以在這里為大家介紹一下:
BOOL TerminateThread(HANDLE hThread,DWORD dwExitCode); //強行停止線程 //說明:返回值代表是否成功 //參數:HANDLE指針代表需要結束的線程,DWORD數值代表該線程的退出值 //功能:在任何位置結束任何線程
那么,關於多線程的基本C++API就講完了,那么我要說一個關鍵字——volatile。它代表“易變的”,編譯器不會優化使用這個關鍵字生命的全局變量,保證此變量完全“聽你的話”。那么,就可以實現簡單的線程間通訊。接着,來寫一個比較簡單的例程,本來是Java1234的多線程例程,現在被我改成了C++版本。請看:
//多線程搶占輸出 #include <iostream> #include <windows.h> using namespace std; void ThreadUser(){ //線程入口 cout<<"子線程開始"<<"\n"; for(int i=0;i<100;++i){ //搶占循環 cout<<"子線程第"<<i<<"次循環搶占;"<<"\n"; //輸出信息 Sleep(100); //搶占延時 } cout<<"子線程結束"<<"\n"; } int main(){ cout<<"主線程開始"<<"\n"; HANDLE h; //線程句柄 CreateThread(null,0,(LPTHREAD_START_ROUTINE)ThreadUser,null,1,0); //創建子線程 ResumeThread(HANDLE); //啟動子線程 for(int i=0;i<100;++i){ //搶占循環 cout<<"主線程第"<<i<<"次循環搶占;"<<"\n"; //輸出信息 Sleep(100); //搶占延時 } Sleep(1000); //等待子線程 delete h; //回收子線程資源 cout<<"主線程結束"<<"\n"; system("pause"); return 0; }
好了,我們的多線程就先講到這里,下次再見。
順便說一下,我們的老朋友windows XP今天退役了,大家默哀一下吧……
歡迎繼續關注BKMMSC-金雞獨立的博客。再見!