線程是進程的一條執行路徑
它包含獨立的堆棧和CPU寄存器狀態
每個線程共享所有的進程資源
包括打開的文件
信號標識及動態分配的內存等
一個進程內的所有線程使用同一個地址空間
而這些線程的執行由系統調度程序控制
調度程序決定哪個線程可執行以及什麼時候執行線程
線程有優先級別
優先權較低的線程必須等到優先權較高的線程執行完後再執行
在多處理器的機器上
調度程序可將多個線程放到不同的處理器上去運行
這樣可使處理器任務平衡
並提高系統的運行效率
Windows是一種多任務的操作系統
在Windows的一個進程內包含一個或多個線程
位Windows環境下的Win
API提供了多線程應用程序開發所需要的接口函數
而利用VC中提供的標准C庫也可以開發多線程應用程序
相應的MFC類庫封裝了多線程編程的類
用戶在開發時可根據應用程序的需要和特點選擇相應的工具
為了使大家能全面地了解Windows多線程編程技術
本文將重點介紹Win
API和MFC兩種方式下如何編制多線程程序
多線程編程在Win
方式下和MFC類庫支持下的原理是一致的
進程的主線程在任何需要的時候都可以創建新的線程
當線程執行完後
自動終止線程; 當進程結束後
所有的線程都終止
所有活動的線程共享進程的資源
因此
在編程時需要考慮在多個線程訪問同一資源時產生沖突的問題
當一個線程正在訪問某進程對象
而另一個線程要改變該對象
就可能會產生錯誤的結果
編程時要解決這個沖突
Win
API下的多線程編程
Win
API是Windows操作系統內核與應用程序之間的界面
它將內核提供的功能進行函數包裝
應用程序通過調用相關函數而獲得相應的系統功能
為了向應用程序提供多線程功能
Win
API函數集中提供了一些處理多線程程序的函數集
直接用Win
API進行程序設計具有很多優點: 基於Win
的應用程序執行代碼小
運行效率高
但是它要求程序員編寫的代碼較多
且需要管理所有系統提供給程序的資源
用Win
API直接編寫程序要求程序員對Windows系統內核有一定的了解
會占用程序員很多時間對系統資源進行管理
因而程序員的工作效率降低
用Win
函數創建和終止線程
Win
函數庫中提供了操作多線程的函數
包括創建線程
終止線程
建立互斥區等
在應用程序的主線程或者其他活動線程中創建新的線程的函數如下
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes
DWORD dwStackSize
LPTHREAD_START_ROUTINE lpStartAddress
LPVOID lpParameter
DWORD dwCreationFlags
LPDWORD lpThreadId);
如果創建成功則返回線程的句柄
否則返回NULL
創建了新的線程後
該線程就開始啟動執行了
但如果在dwCreationFlags中使用了CREATE_SUSPENDED特性
那麼線程並不馬上執行
而是先掛起
等到調用ResumeThread後才開始啟動線程
在這個過程中可以調用下面這個函數來設置線程的優先權
BOOL SetThreadPriority(HANDLE hThread
int nPriority);
當調用線程的函數返回後
線程自動終止
如果需要在線程的執行過程中終止則可調用函數
VOID ExitThread(DWORD dwExitCode);
如果在線程的外面終止線程
則可調用下面的函數
BOOL TerminateThread(HANDLE hThread
DWORD dwExitCode);
但應注意: 該函數可能會引起系統不穩定
而且線程所占用的資源也不釋放
因此
一般情況下
建議不要使用該函數
如果要終止的線程是進程內的最後一個線程
則線程被終止後相應的進程也應終止
線程的同步
在線程體內
如果該線程完全獨立
與其他線程沒有數據存取等資源操作上的沖突
則可按照通常單線程的方法進行編程
但是
在多線程處理時情況常常不是這樣
線程之間經常要同時訪問一些資源
由於對共享資源進行訪問引起沖突是不可避免的
為了解決這種線程同步問題
Win
API提供了多種同步控制對象來幫助程序員解決共享資源訪問沖突
在介紹這些同步對象之前先介紹一下等待函數
因為所有控制對象的訪問控制都要用到這個函數
Win
API提供了一組能使線程阻塞其自身執行的等待函數
這些函數在其參數中的一個或多個同步對象產生了信號
或者超過規定的等待時間才會返回
在等待函數未返回時
線程處於等待狀態
此時線程只消耗很少的CPU時間
使用等待函數既可以保證線程的同步
又可以提高程序的運行效率
最常用的等待函數是
DWORD WaitForSingleObject(HANDLE hHandle
DWORD dwMilliseconds);
而函數WaitForMultipleObject可以用來同時監測多個同步對象
該函數的聲明為
DWORD WaitForMultipleObject(DWORD nCount
CONST HANDLE *lpHandles
BOOL bWaitAll
DWORD dwMilliseconds);
(
)互斥體對象
Mutex對象的狀態在它不被任何線程擁有時才有信號
而當它被擁有時則無信號
Mutex對象很適合用來協調多個線程對共享資源的互斥訪問
可按下列步驟使用該對象
首先
建立互斥體對象
得到句柄
HANDLE CreateMutex();
然後
在線程可能產生沖突的區域前(即訪問共享資源之前)調用WaitForSingleObject
將句柄傳給函數
請求占用互斥對象
dwWaitResult = WaitForSingleObject(hMutex
L);
共享資源訪問結束
釋放對互斥體對象的占用
ReleaseMutex(hMutex);
互斥體對象在同一時刻只能被一個線程占用
當互斥體對象被一個線程占用時
若有另一線程想占用它
則必須等到前一線程釋放後才能成功
(
)信號對象
信號對象允許同時對多個線程共享資源進行訪問
在創建對象時指定最大可同時訪問的線程數
當一個線程申請訪問成功後
信號對象中的計數器減一
調用ReleaseSemaphore函數後
信號對象中的計數器加一
其中
計數器值大於或等於0
但小於或等於創建時指定的最大值
如果一個應用在創建一個信號對象時
將其計數器的初始值設為0
就阻塞了其他線程
保護了資源
等初始化完成後
調用ReleaseSemaphore函數將其計數器增加至最大值
則可進行正常的存取訪問
可按下列步驟使用該對象
首先
創建信號對象
HANDLE CreateSemaphore();
或者打開一個信號對象
HANDLE OpenSemaphore();
然後
在線程訪問共享資源之前調用WaitForSingleObject
共享資源訪問完成後
應釋放對信號對象的占用
ReleaseSemaphore();
(
)事件對象
事件對象(Event)是最簡單的同步對象
它包括有信號和無信號兩種狀態
在線程訪問某一資源之前
需要等待某一事件的發生
這時用事件對象最合適
例如
只有在通信端口緩沖區收到數據後
監視線程才被激活
事件對象是用CreateEvent函數建立的
該函數可以指定事件對象的類和事件的初始狀態
如果是手工重置事件
那麼它總是保持有信號狀態
直到用ResetEvent函數重置成無信號的事件
如果是自動重置事件
那麼它的狀態在單個等待線程釋放後會自動變為無信號的
用SetEvent可以把事件對象設置成有信號狀態
在建立事件時
可以為對象命名
這樣其他進程中的線程可以用OpenEvent函數打開指定名字的事件對象句柄
(
)排斥區對象
在排斥區中異步執行時
它只能在同一進程的線程之間共享資源處理
雖然此時上面介紹的幾種方法均可使用
但是
使用排斥區的方法則使同步管理的效率更高
使用時先定義一個CRITICAL_SECTION結構的排斥區對象
在進程使用之前調用如下函數對對象進行初始化:
VOID InitializeCriticalSection(LPCRITICAL_SECTION);
當一個線程使用排斥區時
調用函數
EnterCriticalSection或者TryEnterCriticalSection;
當要求占用
退出排斥區時
調用函數LeaveCriticalSection
釋放對排斥區對象的占用
供其他線程使用
基於MFC的多線程編程
MFC是微軟的VC開發集成環境中提供給程序員的基礎函數庫
它用類庫的方式將Win
API進行封裝
以類的方式提供給開發者
由於其快速
簡捷
功能強大等特點深受廣大開發者喜愛
因此
建議使用MFC類庫進行應用程序的開發
在VC++附帶的MFC類庫中
提供了對多線程編程的支持
基本原理與基於Win
API的設計一致
但由於MFC對同步對象做了封裝
因此實現起來更加方便
避免了對象句柄管理上的煩瑣工作
在MFC中
線程分為兩種
工作線程和用戶接口線程
工作線程與前面所述的線程一致
用戶接口線程是一種能夠接收用戶的輸入
處理事件和消息的線程
工作線程
工作線程編程較為簡單
設計思路與前面所講的基本一致: 一個基本函數代表了一個線程
創建並啟動線程後
線程進入運行狀態; 如果線程用到共享資源
則需要進行資源同步處理
這種方式創建線程並啟動線程時可調用函數
CWinThread*AfxBeginThread( AFX_THREADPROC pfnThreadProc
LPVOID pParam
int nPriority= THREAD_PRIORITY_NORMAL
UINT nStackSize =
DWORD dwCreateFlags=
LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL);參數pfnThreadProc是線程執行體函數
函數原形為: UINT ThreadFunction( LPVOID pParam)
參數pParam是傳遞給執行函數的參數
<
From:http://tw.wingwit.com/Article/os/xtgl/201311/9522.html