?? mfc教程_ mfc的進程和線程.htm
字號:
to
DLL),DllMain給它分配動態內存并且使用TlsSetValue把線程私有的數據按索引保存。DLL函數可以使用TlsGetValue按索引讀取調用線程的私有數據。</P>
<P align=justify>TLS函數如下:</P>
<UL>
<P align=justify>
<LI>DWORD TlsAlloc()
<P></P></LI></UL>
<P align=justify>在進程或DLL初始化時調用,并且把返回值(索引值)作為全局變量保存。</P>
<UL>
<P align=justify>
<LI>BOOL TlsSetValue(
<P></P></LI></UL>
<DIR>
<P align=justify>DWORD dwTlsIndex, //TLS index to set value for </P>
<P align=justify>LPVOID lpTlsValue //value to be stored </P></DIR>
<P align=justify>);</P>
<P align=justify>其中:</P>
<P align=justify>dwTlsIndex是TlsAlloc分配的索引。</P>
<P align=justify>lpTlsValue是線程在TLS槽中存放的數據指針,指針指向線程要保存的數據。</P>
<P align=justify>線程首先分配動態內存并保存數據到此內存中,然后調用TlsSetValue保存內存指針到TLS槽。</P>
<UL>
<P align=justify>
<LI>LPVOID TlsGetValue(
<P></P></LI></UL>
<P align=justify>DWORD dwTlsIndex // TLS index to retrieve value for</P>
<P align=justify>);</P>
<P align=justify>其中:</P>
<P align=justify>dwTlsIndex是TlsAlloc分配的索引。</P>
<P align=justify>當要存取保存的數據時,使用索引得到數據指針。</P>
<UL>
<P align=justify>
<LI>BOOL TlsFree(
<P></P></LI></UL>
<P align=justify>DWORD dwTlsIndex // TLS index to free</P>
<P align=justify>);</P>
<P align=justify>其中:</P>
<P align=justify>dwTlsIndex是TlsAlloc分配的索引。</P>
<P align=justify>當每一個線程都不再使用局部存儲數據時,線程釋放它分配的動態內存。在TLS索引不再需要時,使用TlsFree釋放索引。</P>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc445889085></A><A name=_Toc445782488></A><A
name=_Toc452640949></A><A name=_Toc457299047></A><B>線程同步</B>
<P></P>
<P
align=justify>同步可以保證在一個時間內只有一個線程對某個資源(如操作系統資源等共享資源)有控制權。共享資源包括全局變量、公共數據成員或者句柄等。同步還可以使得有關聯交互作用的代碼按一定的順序執行。</P>
<P align=justify>Win32提供了一組對象用來實現多線程的同步。</P>
<P align=justify>這些對象有兩種狀態:獲得信號(Signaled)或者沒有或則信號(Not signaled)。線程通過Win32
API提供的同步等待函數(Wait
functions)來使用同步對象。一個同步對象在同步等待函數調用時被指定,調用同步函數地線程被阻塞(blocked),直到同步對象獲得信號。被阻塞的線程不占用CPU時間。</P>
<OL>
<P align=justify>
<LI><A name=_Toc445889086></A><A name=_Toc445782489></A><A
name=_Toc452640950></A><A name=_Toc457299048></A><B>同步對象</B>
<P></P></LI></OL></LI></OL></OL>
<P
align=justify>同步對象有:Critical_section(關鍵段),Event(事件),Mutex(互斥對象),Semaphores(信號量)。</P>
<P align=justify>下面,解釋怎么使用這些同步對象。</P>
<OL>
<P align=justify>
<LI>關鍵段對象:
<P></P>
<P align=justify>首先,定義一個關鍵段對象cs:</P>
<P align=justify>CRITICAL_SECTION cs;</P>
<P align=justify>然后,初始化該對象。初始化時把對象設置為NOT_SINGALED,表示允許線程使用資源:</P>
<P align=justify>InitializeCriticalSection(&cs);</P>
<P
align=justify>如果一段程序代碼需要對某個資源進行同步保護,則這是一段關鍵段代碼。在進入該關鍵段代碼前調用EnterCriticalSection函數,這樣,其他線程都不能執行該段代碼,若它們試圖執行就會被阻塞。</P>
<P
align=justify>完成關鍵段的執行之后,調用LeaveCriticalSection函數,其他的線程就可以繼續執行該段代碼。如果該函數不被調用,則其他線程將無限期的等待。</P>
<P align=justify></P>
<LI>事件對象
<P></P>
<P
align=justify>首先,調用CreateEvent函數創建一個事件對象,該函數返回一個事件句柄。然后,可以設置(SetEvent)或者復位(ResetEvent)一個事件對象,也可以發一個事件脈沖(PlusEvent),即設置一個事件對象,然后復位它。復位有兩種形式:自動復位和人工復位。在創建事件對象時指定復位形式。。</P>
<P
align=justify>自動復位:當對象獲得信號后,就釋放下一個可用線程(優先級別最高的線程;如果優先級別相同,則等待隊列中的第一個線程被釋放)。</P>
<P align=justify>人工復位:當對象獲得信號后,就釋放所有可利用線程。</P>
<P align=justify>最后,使用CloseHandle銷毀創建的事件對象。</P>
<P align=justify></P>
<LI>互斥對象
<P></P>
<P
align=justify>首先,調用CreateMutex創建互斥對象;然后,調用等待函數,可以的話利用關鍵資源;最后,調用RealseMutex釋放互斥對象。</P>
<P align=justify>互斥對象可以在進程間使用,但關鍵段對象只能用于同一進程的線程之間。</P>
<P align=justify></P>
<LI>信號量對象
<P></P>
<P align=justify>在Win32中,信號量的數值變為0時給以信號。在有多個資源需要管理時可以使用信號量對象。</P>
<P
align=justify>首先,調用CreateSemaphore創建一個信號量;然后,調用等待函數,如果允許的話,則利用關鍵資源;最后,調用RealeaseSemaphore釋放信號量對象。</P>
<P align=justify></P>
<LI>此外,還有其他句柄可以用來同步線程:
<P></P></LI></OL>
<P align=justify>文件句柄(FILE HANDLES)</P>
<P align=justify>命名管道句柄(NAMED PIPE HANDELS)</P>
<P align=justify>控制臺輸入緩沖區句柄(CONSOLE INPUT BUFFER HANDLES)</P>
<P align=justify>通訊設備句柄(COMMUNICTION DEVICE HANDLES)</P>
<P align=justify>進程句柄(PROCESS HANDLES)</P>
<P align=justify>線程句柄(THREAD HANDLES)</P>
<P align=justify>例如,當一個進程或線程結束時,進程或線程句柄獲得信號,等待該進程或者線程結束的線程被釋放。</P>
<OL>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc445889087></A><A name=_Toc445782490></A><A
name=_Toc452640951></A><A name=_Toc457299049></A><B>等待函數</B>
<P></P></LI></OL></OL></OL>
<P align=justify>Win32提供了一組等待函數用來讓一個線程阻塞自己的執行。等待函數分三類:</P>
<OL>
<P align=justify>
<LI>等待單個對象的(FOR SINGLE OBJECT):
<P></P>
<P align=justify>這類函數包括:</P>
<P align=justify>SignalObjectAndWait</P>
<P align=justify>WaitForSingleObject</P>
<P align=justify>WaitForSingleObjectEx</P>
<P align=justify>函數參數包括同步對象的句柄和等待時間等。</P>
<P align=justify>在以下情況下等待函數返回:</P>
<P align=justify>同步對象獲得信號時返回;</P>
<P
align=justify>等待時間達到了返回:如果等待時間不限制(Infinite),則只有同步對象獲得信號才返回;如果等待時間為0,則在測試了同步對象的狀態之后馬上返回。</P>
<P align=justify></P>
<LI>等待多個對象的(FOR MULTIPLE OBJECTS)
<P></P>
<P align=justify>這類函數包括:</P>
<P align=justify>WaitForMultipleObjects</P>
<P align=justify>WaitForMultipleObjectsEx</P>
<P align=justify>MsgWaitForMultipleObjects</P>
<P align=justify>MsgWaitForMultipleObjectsEx</P>
<P align=justify>函數參數包括同步對象的句柄,等待時間,是等待一個還是多個同步對象等等。</P>
<P align=justify>在以下情況下等待函數返回:</P>
<P align=justify>一個或全部同步對象獲得信號時返回(在參數中指定是等待一個或多個同步對象);</P>
<P
align=justify>等待時間達到了返回:如果等待時間不限制(Infinite),則只有同步對象獲得信號才返回;如果等待時間為0,則在測試了同步對象的狀態之后馬上返回。</P>
<P align=justify></P>
<LI>可以發出提示的函數(ALTERABLE)
<P></P></LI></OL>
<P align=justify>這類函數包括:</P>
<P align=justify>MsgWaitForMultipleObjectsEx</P>
<P align=justify>SignalObjectAndWait</P>
<P align=justify>WaitForMultipleObjectsEx</P>
<P align=justify>WaitForSingleObjectEx</P>
<P align=justify>這些函數主要用于重疊(Overlapped)的I/O(異步I/O)。</P>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc445889088></A><A name=_Toc445782491></A><A
name=_Toc452640952></A><A name=_Toc457299050></A><B>MFC的線程處理</B>
<P></P>
<P align=justify>在Win32
API的基礎之上,MFC提供了處理線程的類和函數。處理線程的類是CWinThread,函數是AfxBeginThread、AfxEndThread等。</P>
<P align=justify>表5-6解釋了CWinThread的成員變量和函數。</P>
<P
align=justify>CWinThread是MFC線程類,它的成員變量m_hThread和m_hThreadID是對應的Win32線程句柄和線程ID。</P>
<P align=justify>MFC明確區分兩種線程:用戶界面線程(User interface thread)和工作者線程(Worker
thread)。用戶界面線程一般用于處理用戶輸入并對用戶產生的事件和消息作出應答。工作者線程用于完成不要求用戶輸入的任務,如耗時計算。</P>
<P align=justify>Win32
API并不區分線程類型,它只需要知道線程的開始地址以便它開始執行線程。MFC為用戶界面線程特別地提供消息泵來處理用戶界面的事件。CWinApp對象是用戶界面線程對象的一個例子,CWinApp從類CWinThread派生并處理用戶產生的事件和消息。</P>
<OL>
<P align=justify>
<LI><A name=_Toc445889089></A><A name=_Toc445782492></A><A
name=_Toc452640953></A><A name=_Toc457299051></A><B>創建用戶界面線程</B>
<P></P></LI></OL></LI></OL></OL>
<P align=justify>通過以下步驟創建一個用戶界面線程:</P>
<UL>
<P align=justify>
<LI>從CWinThread派生一個有動態創建能力的類。使用DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE宏來支持動態創建。
<P></P>
<P align=justify></P>
<LI>覆蓋CWinThread的一些虛擬函數,可以覆蓋的函數見表5-4關于CWinThread的部分。其中,函數InitInstance是必須覆蓋的,ExitInstance通常是要覆蓋的。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -