C++ 中的多線程


編程思想之多線程與多進程(1)——以操作系統的角度述說線程與進程》一文詳細講述了線程、進程的關系及在操作系統中的表現,《編程思想之多線程與多進程(2)——線程優先級與線程安全》一文講了線程安全(各種同步鎖)和優先級,這是多線程學習必須了解的基礎。本文將接着講一下C++中多線程程序的開發.這里主要講Windows平台線程的用法,創建線程要調用windows API的CreateThread方法。

 

創建線程

在Windows平台,Windows API提供了對多線程的支持。前面進程和線程的概念中我們提到,一個程序至少有一個線程,這個線程稱為主線程(main thread),如果我們不顯示地創建線程,那我們產的程序就是只有主線程的間線程程序。
下面,我們看看Windows中線程相關的操作和方法:

CreateThread與CloseHandle

CreateThread用於創建一個線程,其函數原型如下

**說明:**lpThreadAttributes:指向SECURITY_ATTRIBUTES結構的指針,決定返回的句柄是否可被子進程繼承,如果為NULL則表示返回的句柄不能被子進程繼承。

dwStackSize :線程棧的初始化大小,字節單位。系統分配這個值對

lpStartAddress:指向一個函數指針,該函數將被線程調用執行。因此該函數也被稱為線程函數(ThreadProc),是線程執行的起始地址,線程函數是一個回調函數,由操作系統在線程中調用。線程函數的原型如下: 

lpParameter:傳入線程函數(ThreadProc)的參數,不需傳遞參數時為NULL

dwCreationFlags:控制線程創建的標志,有三個類型,0:線程創建后立即執行線程;CREATE_SUSPENDED:線程創建后進入就緒狀態,直到線程被喚醒時才調用;STACK_SIZE_PARAM_IS_A_RESERVATION:dwStackSize 參數指定線程初始化棧的大小,如果STACK_SIZE_PARAM_IS_A_RESERVATION標志未指定,dwStackSize將會設為系統預留的值。

返回值:如果線程創建成功,則返回這個新線程的句柄,否則返回NULL。如果線程創建失敗,可通過GetLastError函數獲得錯誤信息。

可用這個函數關閉創建的線程句柄,如果函數執行成功則返回true(非0),如果失敗則返回false(0),如果執行失敗可調用GetLastError.函數獲得錯誤信息。

【Demo1】:創建一個最簡單的線程

結果如下:

【Demo2】:在線程函數中傳入參數

結果:

CreateMutex、WaitForSingleObject、ReleaseMutex

從【Demo2】中可以看出,雖然創建的子線程都正常執行起來了,但輸出的結果並不是我們預期的效果。我們預期的效果是每輸出一條語句后自動換行,但結果卻並非都是這樣。這是因為在線程執行時沒有做同步處理,比如第一行的輸出,主線程輸出“主線程 ===”后時間片已用完,這時輪到子線程1輸出,在子線程輸出“線程1 —”后時間片也用完了,這時又輪到主線程執行輸出“0”,之后又輪到子線程1輸出“0”。於是就出現了“主線程 === 線程1 — 0 0”的結果。

主線程:cout << “主線程 === ” << i << endl;
子線程:cout << pThreadData->strThreadName << ” — ” << i << endl;

為避免出現這種情況,我們對線程做一些簡單的同步處理,這里我們用互斥量(Mutex),關於互斥量(Mutex)的概念,請看《編程思想之多線程與多進程(2)——線程優先級與線程安全》一文;更多C++線程同步的處理,請看下一節。

在使用互斥量進行線程同步時會用到以下幾個函數:

**說明:**lpMutexAttributes也是表示安全的結構,與CreateThread中的lpThreadAttributes功能相同,表示決定返回的句柄是否可被子進程繼承,如果為NULL則表示返回的句柄不能被子進程繼承。bInitialOwner表示創建Mutex時的當前線程是否擁有Mutex的所有權,若為TRUE則指定為當前的創建線程為Mutex對象的所有者,其它線程訪問需要先ReleaseMutex。lpName為Mutex的名稱。

**說明:**WaitForSingleObject的作用是等待一個指定的對象(如Mutex對象),直到該對象處於非占用的狀態(如Mutex對象被釋放)或超出設定的時間間隔。除此之外,還有一個與它類似的函數WaitForMultipleObjects,它的作用是等待一個或所有指定的對象,直到所有的對象處於非占用的狀態,或超出設定的時間間隔。

hHandle:要等待的指定對象的句柄。dwMilliseconds:超時的間隔,以毫秒為單位;如果dwMilliseconds為非0,則等待直到dwMilliseconds時間間隔用完或對象變為非占用的狀態,如果dwMilliseconds 為INFINITE則表示無限等待,直到等待的對象處於非占用的狀態。

說明:釋放所擁有的互斥量鎖對象,hMutex為釋放的互斥量的句柄。

【Demo3】:線程同步 

結果: 

為進一步理解線程同步的重要性和互斥量的使用方法,我們再來看一個例子。

買火車票是大家春節回家最為關注的事情,我們就簡單模擬一下火車票的售票系統(為使程序簡單,我們就抽出最簡單的模型進行模擬):有500張從北京到贛州的火車票,在8個窗口同時出售,保證系統的穩定性和數據的原子性。

【Demo4】:模擬火車售票系統

SaleTickets.cpp :

測試程序:

結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM