青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 131, comments - 12, trackbacks - 0, articles - 0
  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

MFC 多線程及線程同步

Posted on 2013-01-15 10:02 盛勝 閱讀(479) 評論(1)  編輯 收藏 引用
http://www.cnblogs.com/zqrferrari/archive/2010/07/07/1773113.html
MFC 多線程及線程同步

一、MFC對多線程編程的支持

  MFC中有兩類線程,分別稱之為工作者線程和用戶界面線程。二者的主要區(qū)別在于工作者線程沒有消息循環(huán),而用戶界面線程有自己的消息隊列和消息循環(huán)。
  工作者線程沒有消息機制,通常用來執(zhí)行后臺計算和維護(hù)任務(wù),如冗長的計算過程,打印機的后臺打印等。用戶界面線程一般用于處理獨立于其他線程執(zhí)行之外的用戶輸入,響應(yīng)用戶及系統(tǒng)所產(chǎn)生的事件和消息等。但對于Win32的API編程而言,這兩種線程是沒有區(qū)別的,它們都只需線程的啟動地址即可啟動線程來執(zhí)行任務(wù)。
  在MFC中,一般用全局函數(shù)AfxBeginThread()來創(chuàng)建并初始化一個線程的運行,該函數(shù)有兩種重載形式,分別用于創(chuàng)建工作者線程和用戶界面線程。兩種重載函數(shù)原型和參數(shù)分別說明如下:

  (1) CWinThread* AfxBeginThread(

        AFX_THREADPROC pfnThreadProc,
            LPVOID pParam,
            int nPriority = THREAD_PRIORITY_NORMAL,
            UNT nStackSize = 0,
            DWORD dwCreateFlags = 0,
            LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
           );//用于創(chuàng)建工作者線程

  PfnThreadProc:指向工作者線程的執(zhí)行函數(shù)的指針,線程函數(shù)原型必須聲明如下:

  UINT ExecutingFunction(LPVOID pParam);

  請注意,ExecutingFunction()應(yīng)返回一個UINT類型的值,用以指明該函數(shù)結(jié)束的原因。一般情況下,返回0表明執(zhí)行成功。

  • pParam:      一個32位參數(shù),執(zhí)行函數(shù)將用某種方式解釋該值。它可以是數(shù)值,或是指向一個結(jié)構(gòu)的指針,甚至可以被忽略;
  • nPriority:     線程的優(yōu)先級。如果為0,則線程與其父線程具有相同的優(yōu)先級;
  • nStackSize:   線程為自己分配堆棧的大小,其單位為字節(jié)。如果nStackSize被設(shè)為0,則線程的堆棧被設(shè)置成與父線程堆棧相同大小;
  • dwCreateFlags:如果為0,則線程在創(chuàng)建后立刻開始執(zhí)行。如果為CREATE_SUSPEND,則線程在創(chuàng)建后立刻被掛起;
  • lpSecurityAttrs:線程的安全屬性指針,一般為NULL;

  (2) CWinThread* AfxBeginThread(

       CRuntimeClass* pThreadClass,
            int nPriority = THREAD_PRIORITY_NORMAL,
            UNT nStackSize = 0,
            DWORD dwCreateFlags = 0,
            LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL
           ); 

  pThreadClass 是指向 CWinThread 的一個導(dǎo)出類的運行時類對象的指針,該導(dǎo)出類定義了被創(chuàng)建的用戶界面線程的啟動、退出等;其它參數(shù)的意義同形式1。使用函數(shù)的這個原型生成的線程也有消息機制,在以后的例子中我們將發(fā)現(xiàn)同主線程的機制幾乎一樣。

  下面我們對CWinThread類的數(shù)據(jù)成員及常用函數(shù)進(jìn)行簡要說明。

  • m_hThread:     當(dāng)前線程的句柄;
  • m_nThreadID:   當(dāng)前線程的ID;
  • m_pMainWnd: 指向應(yīng)用程序主窗口的指針
  BOOL CWinThread::CreateThread(DWORD dwCreateFlags=0,UINT nStackSize=0,LPSECURITY_ATTRIBUTES lpSecurityAttrs=NULL);

  該函數(shù)中的dwCreateFlags、nStackSize、lpSecurityAttrs參數(shù)和API函數(shù)CreateThread中的對應(yīng)參數(shù)有相同含義,該函數(shù)執(zhí)行成功,返回非0值,否則返回0。
  一般情況下,調(diào)用AfxBeginThread()來一次性地創(chuàng)建并啟動一個線程,但是也可以通過兩步法來創(chuàng)建線程:首先創(chuàng)建CWinThread類的一個對象,然后調(diào)用該對象的成員函數(shù)CreateThread()來啟動該線程。

  virtual BOOL CWinThread::InitInstance();

  重載該函數(shù)以控制用戶界面線程實例的初始化。初始化成功則返回非0值,否則返回0。用戶界面線程經(jīng)常重載該函數(shù),工作者線程一般不使用InitInstance()。

  virtual int CWinThread::ExitInstance();

  在線程終結(jié)前重載該函數(shù)進(jìn)行一些必要的清理工作。該函數(shù)返回線程的退出碼,0表示執(zhí)行成功,非0值用來標(biāo)識各種錯誤。同InitInstance()成員函數(shù)一樣,該函數(shù)也只適用于用戶界面線程。

 

二、MFC中線程同步

 在程序中使用多線程時,一般很少有多個線程能在其生命期內(nèi)進(jìn)行完全獨立的操作。更多的情況是一些線程進(jìn)行某些處理操作,而其他的線程必須對其處理結(jié)果進(jìn)行了解。正常情況下對這種處理結(jié)果的了解應(yīng)當(dāng)在其處理任務(wù)完成后進(jìn)行。
  如果不采取適當(dāng)?shù)拇胧渌€程往往會在線程處理任務(wù)結(jié)束前就去訪問處理結(jié)果,這就很有可能得到有關(guān)處理結(jié)果的錯誤了解。例如,多個線程同時訪問同一個全局變量,如果都是讀取操作,則不會出現(xiàn)問題。如果一個線程負(fù)責(zé)改變此變量的值,而其他線程負(fù)責(zé)同時讀取變量內(nèi)容,則不能保證讀取到的數(shù)據(jù)是經(jīng)過寫線程修改后的。
  為了確保讀線程讀取到的是經(jīng)過修改的變量,就必須在向變量寫入數(shù)據(jù)時禁止其他線程對其的任何訪問,直至賦值過程結(jié)束后再解除對其他線程的訪問限制。象這種保證線程能了解其他線程任務(wù)處理結(jié)束后的處理結(jié)果而采取的保護(hù)措施即為線程同步。
  線程的同步可分用戶模式的線程同步和內(nèi)核對象的線程同步兩大類。用戶模式中線程的同步方法主要有原子訪問和臨界區(qū)等方法。其特點是同步速度特別快,適合于對線程運行速度有嚴(yán)格要求的場合。
  內(nèi)核對象的線程同步則主要由事件、等待定時器、信號量以及信號燈等內(nèi)核對象構(gòu)成。由于這種同步機制使用了內(nèi)核對象,使用時必須將線程從用戶模式切換到內(nèi)核模式,而這種轉(zhuǎn)換一般要耗費近千個CPU周期,因此同步速度較慢,但在適用性上卻要遠(yuǎn)優(yōu)于用戶模式的線程同步方式。

  

  1.臨界區(qū)
 
 臨界區(qū)(Critical Section)是一段獨占對某些共享資源訪問的代碼,在任意時刻只允許一個線程對共享資源進(jìn)行訪問。如果有多個線程試圖同時訪問臨界區(qū),那么在有一個線程進(jìn)入后其他所有試圖訪問此臨界區(qū)的線程將被掛起,并一直持續(xù)到進(jìn)入臨界區(qū)的線程離開。臨界區(qū)在被釋放后,其他線程可以繼續(xù)搶占,并以此達(dá)到用原子方式操作共享資源的目的。
  臨界區(qū)在使用時以CRITICAL_SECTION結(jié)構(gòu)對象保護(hù)共享資源,并分別用EnterCriticalSection()和LeaveCriticalSection()函數(shù)去標(biāo)識和釋放一個臨界區(qū)。所用到的CRITICAL_SECTION結(jié)構(gòu)對象必須經(jīng)過InitializeCriticalSection()的初始化后才能使用,而且必須確保所有線程中的任何試圖訪問此共享資源的代碼都處在此臨界區(qū)的保護(hù)之下。否則臨界區(qū)將不會起到應(yīng)有的作用,共享資源依然有被破壞的可能。

代碼
  在使用臨界區(qū)時,一般不允許其運行時間過長,只要進(jìn)入臨界區(qū)的線程還沒有離開,其他所有試圖進(jìn)入此臨界區(qū)的線程都會被掛起而進(jìn)入到等待狀態(tài),并會在一定程度上影響。程序的運行性能。尤其需要注意的是不要將等待用戶輸入或是其他一些外界干預(yù)的操作包含到臨界區(qū)。如果進(jìn)入了臨界區(qū)卻一直沒有釋放,同樣也會引起其他線程的長時間等待。換句話說,在執(zhí)行了EnterCriticalSection()語句進(jìn)入臨界區(qū)后無論發(fā)生什么,必須確保與之匹配的LeaveCriticalSection()都能夠被執(zhí)行到。可以通過添加結(jié)構(gòu)化異常處理代碼來確保LeaveCriticalSection()語句的執(zhí)行。雖然臨界區(qū)同步速度很快,但卻只能用來同步本進(jìn)程內(nèi)的線程,而不可用來同步多個進(jìn)程中的線程。
  MFC為臨界區(qū)提供有一個CCriticalSection類,使用該類進(jìn)行線程同步處理是非常簡單的,只需在線程函數(shù)中用CCriticalSection類成員函數(shù)Lock()和UnLock()標(biāo)定出被保護(hù)代碼片段即可。對于上述代碼,可通過CCriticalSection類將其改寫如下:

代碼

 

  2.事件內(nèi)核對象

  在前面講述線程通信時曾使用過事件內(nèi)核對象來進(jìn)行線程間的通信,除此之外,事件內(nèi)核對象也可以通過通知操作的方式來保持線程的同步。對于前面那段使用臨界區(qū)保持線程同步的代碼可用事件對象的線程同步方法改寫如下:

代碼

  在創(chuàng)建線程前,首先創(chuàng)建一個可以自動復(fù)位的事件內(nèi)核對象hEvent,而線程函數(shù)則通過WaitForSingleObject()等待函數(shù)無限等待hEvent的置位,只有在事件置位時WaitForSingleObject()才會返回,被保護(hù)的代碼將得以執(zhí)行。對于以自動復(fù)位方式創(chuàng)建的事件對象,在其置位后一被WaitForSingleObject()等待到就會立即復(fù)位,也就是說在執(zhí)行ThreadProc12()中的受保護(hù)代碼時,事件對象已經(jīng)是復(fù)位狀態(tài)的,這時即使有ThreadProc13()對CPU的搶占,也會由于WaitForSingleObject()沒有hEvent的置位而不能繼續(xù)執(zhí)行,也就沒有可能破壞受保護(hù)的共享資源。在ThreadProc12()中的處理完成后可以通過SetEvent()對hEvent的置位而允許ThreadProc13()對共享資源g_cArray的處理。這里SetEvent()所起的作用可以看作是對某項特定任務(wù)完成的通知。
  使用臨界區(qū)只能同步同一進(jìn)程中的線程,而使用事件內(nèi)核對象則可以對進(jìn)程外的線程進(jìn)行同步,其前提是得到對此事件對象的訪問權(quán)。可以通過OpenEvent()函數(shù)獲取得到,其函數(shù)原型為:

HANDLE OpenEvent(
 DWORD dwDesiredAccess,  
// 訪問標(biāo)志
 BOOL bInheritHandle,    // 繼承標(biāo)志
 LPCTSTR lpName          // 指向事件對象名的指針
); 
  如果事件對象已創(chuàng)建(在創(chuàng)建事件時需要指定事件名),函數(shù)將返回指定事件的句柄。對于那些在創(chuàng)建事件時沒有指定事件名的事件內(nèi)核對象,可以通過使用內(nèi)核對象的繼承性或是調(diào)用DuplicateHandle()函數(shù)來調(diào)用CreateEvent()以獲得對指定事件對象的訪問權(quán)。在獲取到訪問權(quán)后所進(jìn)行的同步操作與在同一個進(jìn)程中所進(jìn)行的線程同步操作是一樣的。
  如果需要在一個線程中等待多個事件,則用WaitForMultipleObjects()來等待。WaitForMultipleObjects()與WaitForSingleObject()類似,同時監(jiān)視位于句柄數(shù)組中的所有句柄。這些被監(jiān)視對象的句柄享有平等的優(yōu)先權(quán),任何一個句柄都不可能比其他句柄具有更高的優(yōu)先權(quán)。WaitForMultipleObjects()的函數(shù)原型為:
DWORD WaitForMultipleObjects(
 DWORD nCount,              
// 等待句柄數(shù)
 CONST HANDLE *lpHandles,   // 句柄數(shù)組首地址
 BOOL fWaitAll,             // 等待標(biāo)志
 DWORD dwMilliseconds       // 等待時間間隔
);

  參數(shù)nCount指定了要等待的內(nèi)核對象的數(shù)目,存放這些內(nèi)核對象的數(shù)組由lpHandles來指向。fWaitAll對指定的這nCount個內(nèi)核對象的兩種等待方式進(jìn)行了指定,為TRUE時當(dāng)所有對象都被通知時函數(shù)才會返回,為FALSE則只要其中任何一個得到通知就可以返回。dwMilliseconds在這里的作用與在WaitForSingleObject()中的作用是完全一致的。如果等待超時,函數(shù)將返回WAIT_TIMEOUT。如果返回WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1中的某個值,則說明所有指定對象的狀態(tài)均為已通知狀態(tài)(當(dāng)fWaitAll為TRUE時)或是用以減去WAIT_OBJECT_0而得到發(fā)生通知的對象的索引(當(dāng)fWaitAll為FALSE時)。如果返回值在WAIT_ABANDONED_0與WAIT_ABANDONED_0+nCount-1之間,則表示所有指定對象的狀態(tài)均為已通知,且其中至少有一個對象是被丟棄的互斥對象(當(dāng)fWaitAll為TRUE時),或是用以減去WAIT_OBJECT_0表示一個等待正常結(jié)束的互斥對象的索引(當(dāng)fWaitAll為FALSE時)。 下面給出的代碼主要展示了對WaitForMultipleObjects()函數(shù)的使用。通過對兩個事件內(nèi)核對象的等待來控制線程任務(wù)的執(zhí)行與中途退出:

代碼

  MFC為事件相關(guān)處理也提供了一個CEvent類,共包含有除構(gòu)造函數(shù)外的4個成員函數(shù)PulseEvent()、ResetEvent()、SetEvent()和UnLock()。在功能上分別相當(dāng)與Win32 API的PulseEvent()、ResetEvent()、SetEvent()和CloseHandle()等函數(shù)。而構(gòu)造函數(shù)則履行了原CreateEvent()函數(shù)創(chuàng)建事件對象的職責(zé),其函數(shù)原型為:
  CEvent(BOOL bInitiallyOwn = FALSE, BOOL bManualReset = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );

 

  3.信號量內(nèi)核對象

  信號量(Semaphore)內(nèi)核對象對線程的同步方式與前面幾種方法不同,它允許多個線程在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大線程數(shù)目。在用CreateSemaphore()創(chuàng)建信號量時即要同時指出允許的最大資源計數(shù)和當(dāng)前可用資源計數(shù)。一般是將當(dāng)前可用資源計數(shù)設(shè)置為最大資源計數(shù),每增加一個線程對共享資源的訪問,當(dāng)前可用資源計數(shù)就會減1,只要當(dāng)前可用資源計數(shù)是大于0的,就可以發(fā)出信號量信號。但是當(dāng)前可用計數(shù)減小到0時則說明當(dāng)前占用資源的線程數(shù)已經(jīng)達(dá)到了所允許的最大數(shù)目,不能在允許其他線程的進(jìn)入,此時的信號量信號將無法發(fā)出。線程在處理完共享資源后,應(yīng)在離開的同時通過ReleaseSemaphore()函數(shù)將當(dāng)前可用資源計數(shù)加1。在任何時候當(dāng)前可用資源計數(shù)決不可能大于最大資源計數(shù)。
  使用信號量內(nèi)核對象進(jìn)行線程同步主要會用到CreateSemaphore()、OpenSemaphore()、ReleaseSemaphore()、WaitForSingleObject()和WaitForMultipleObjects()等函數(shù)。其中,CreateSemaphore()用來創(chuàng)建一個信號量內(nèi)核對象,其函數(shù)原型為:

HANDLE CreateSemaphore(
 LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, 
// 安全屬性指針
 LONG lInitialCount,               // 初始計數(shù)
 LONG lMaximumCount,               // 最大計數(shù)
 LPCTSTR lpName                  // 對象名指針
);  

  參數(shù)lMaximumCount是一個有符號32位值,定義了允許的最大資源計數(shù),最大取值不能超過4294967295。lpName參數(shù)可以為創(chuàng)建的信號量定義一個名字,由于其創(chuàng)建的是一個內(nèi)核對象,因此在其他進(jìn)程中可以通過該名字而得到此信號量。OpenSemaphore()函數(shù)即可用來根據(jù)信號量名打開在其他進(jìn)程中創(chuàng)建的信號量,函數(shù)原型如下:

HANDLE OpenSemaphore(
 DWORD dwDesiredAccess,   
// 訪問標(biāo)志
 BOOL bInheritHandle,    // 繼承標(biāo)志
 LPCTSTR lpName        // 信號量名
); 

  在線程離開對共享資源的處理時,必須通過ReleaseSemaphore()來增加當(dāng)前可用資源計數(shù)。否則將會出現(xiàn)當(dāng)前正在處理共享資源的實際線程數(shù)并沒有達(dá)到要限制的數(shù)值,而其他線程卻因為當(dāng)前可用資源計數(shù)為0而仍無法進(jìn)入的情況。ReleaseSemaphore()的函數(shù)原型為:

BOOL ReleaseSemaphore(
 HANDLE hSemaphore, 
   // 信號量句柄
 LONG lReleaseCount,   // 計數(shù)遞增數(shù)量
 LPLONG lpPreviousCount  // 先前計數(shù)
);

  該函數(shù)將lReleaseCount中的值添加給信號量的當(dāng)前資源計數(shù),一般將lReleaseCount設(shè)置為1,如果需要也可以設(shè)置其他的值。WaitForSingleObject()和WaitForMultipleObjects()主要用在試圖進(jìn)入共享資源的線程函數(shù)入口處,主要用來判斷信號量的當(dāng)前可用資源計數(shù)是否允許本線程的進(jìn)入。只有在當(dāng)前可用資源計數(shù)值大于0時,被監(jiān)視的信號量內(nèi)核對象才會得到通知。
  信號量的使用特點使其更適用于對Socket(套接字)程序中線程的同步。例如,網(wǎng)絡(luò)上的HTTP服務(wù)器要對同一時間內(nèi)訪問同一頁面的用戶數(shù)加以限制,這時可以為沒一個用戶對服務(wù)器的頁面請求設(shè)置一個線程,而頁面則是待保護(hù)的共享資源,通過使用信號量對線程的同步作用可以確保在任一時刻無論有多少用戶對某一頁面進(jìn)行訪問,只有不大于設(shè)定的最大用戶數(shù)目的線程能夠進(jìn)行訪問,而其他的訪問企圖則被掛起,只有在有用戶退出對此頁面的訪問后才有可能進(jìn)入。下面給出的示例代碼即展示了類似的處理過程:

代碼

  在MFC中,通過CSemaphore類對信號量作了表述。該類只具有一個構(gòu)造函數(shù),可以構(gòu)造一個信號量對象,并對初始資源計數(shù)、最大資源計數(shù)、對象名和安全屬性等進(jìn)行初始化,其原型如下:

   CSemaphore( LONG lInitialCount = 1, LONG lMaxCount = 1, LPCTSTR pstrName = NULL, LPSECURITY_ATTRIBUTES lpsaAttributes = NULL );

  在構(gòu)造了CSemaphore類對象后,任何一個訪問受保護(hù)共享資源的線程都必須通過CSemaphore從父類CSyncObject類繼承得到的Lock()和UnLock()成員函數(shù)來訪問或釋放CSemaphore對象。與前面介紹的幾種通過MFC類保持線程同步的方法類似,通過CSemaphore類也可以將前面的線程同步代碼進(jìn)行改寫,這兩種使用信號量的線程同步方法無論是在實現(xiàn)原理上還是從實現(xiàn)結(jié)果上都是完全一致的。下面給出經(jīng)MFC改寫后的信號量線程同步代碼:

代碼

 

     4.互斥內(nèi)核對象

     互斥(Mutex)是一種用途非常廣泛的內(nèi)核對象。能夠保證多個線程對同一共享資源的互斥訪問。同臨界區(qū)有些類似,只有擁有互斥對象的線程才具有訪問資源的權(quán)限,由于互斥對象只有一個,因此就決定了任何情況下此共享資源都不會同時被多個線程所訪問。當(dāng)前占據(jù)資源的線程在任務(wù)處理完后應(yīng)將擁有的互斥對象交出,以便其他線程在獲得后得以訪問資源。與其他幾種內(nèi)核對象不同,互斥對象在操作系統(tǒng)中擁有特殊代碼,并由操作系統(tǒng)來管理,操作系統(tǒng)甚至還允許其進(jìn)行一些其他內(nèi)核對象所不能進(jìn)行的非常規(guī)操作。

     以互斥內(nèi)核對象來保持線程同步可能用到的函數(shù)主要有CreateMutex()、OpenMutex()、ReleaseMutex()、WaitForSingleObject()和WaitForMultipleObjects()等。在使用互斥對象前,首先要通過CreateMutex()或OpenMutex()創(chuàng)建或打開一個互斥對象。CreateMutex()函數(shù)原型為:

     HANDLE CreateMutex(
       LPSECURITY_ATTRIBUTES lpMutexAttributes, // 安全屬性指針
       BOOL bInitialOwner, // 初始擁有者
       LPCTSTR lpName // 互斥對象名
     );

     參數(shù)bInitialOwner主要用來控制互斥對象的初始狀態(tài)。一般多將其設(shè)置為FALSE,以表明互斥對象在創(chuàng)建時并沒有為任何線程所占有。如果在創(chuàng)建互斥對象時指定了對象名,那么可以在本進(jìn)程其他地方或是在其他進(jìn)程通過OpenMutex()函數(shù)得到此互斥對象的句柄。OpenMutex()函數(shù)原型為:

    HANDLE OpenMutex(
      DWORD dwDesiredAccess, // 訪問標(biāo)志
      BOOL bInheritHandle, // 繼承標(biāo)志
      LPCTSTR lpName // 互斥對象名
    );

     當(dāng)目前對資源具有訪問權(quán)的線程不再需要訪問此資源而要離開時,必須通過ReleaseMutex()函數(shù)來釋放其擁有的互斥對象,其函數(shù)原型為:

    BOOL ReleaseMutex(HANDLE hMutex);

    其唯一的參數(shù)hMutex為待釋放的互斥對象句柄。至于WaitForSingleObject()和WaitForMultipleObjects()等待函數(shù)在互斥對象保持線程同步中所起的作用與在其他內(nèi)核對象中的作用是基本一致的,也是等待互斥內(nèi)核對象的通知。但是這里需要特別指出的是:在互斥對象通知引起調(diào)用等待函數(shù)返回時,等待函數(shù)的返回值不再是通常的WAIT_OBJECT_0(對于WaitForSingleObject()函數(shù))或是在WAIT_OBJECT_0到WAIT_OBJECT_0+nCount-1之間的一個值(對于WaitForMultipleObjects()函數(shù)),而是將返回一個WAIT_ABANDONED_0(對于WaitForSingleObject()函數(shù))或是在WAIT_ABANDONED_0到WAIT_ABANDONED_0+nCount-1之間的一個值(對于WaitForMultipleObjects()函數(shù))。以此來表明線程正在等待的互斥對象由另外一個線程所擁有,而此線程卻在使用完共享資源前就已經(jīng)終止。除此之外,使用互斥對象的方法在等待線程的可調(diào)度性上同使用其他幾種內(nèi)核對象的方法也有所不同,其他內(nèi)核對象在沒有得到通知時,受調(diào)用等待函數(shù)的作用,線程將會掛起,同時失去可調(diào)度性,而使用互斥的方法卻可以在等待的同時仍具有可調(diào)度性,這也正是互斥對象所能完成的非常規(guī)操作之一。
  在編寫程序時,互斥對象多用在對那些為多個線程所訪問的內(nèi)存塊的保護(hù)上,可以確保任何線程在處理此內(nèi)存塊時都對其擁有可靠的獨占訪問權(quán)。下面給出的示例代碼即通過互斥內(nèi)核對象hMutex對共享內(nèi)存快g_cArray[]進(jìn)行線程的獨占訪問保護(hù)。下面給出實現(xiàn)代碼清單:

代碼
復(fù)制代碼
// 互斥對象
HANDLE hMutex = NULL;
char g_cArray[10];
UINT ThreadProc18(LPVOID pParam)
{
 
// 等待互斥對象通知
 WaitForSingleObject(hMutex, INFINITE);
 
// 對共享資源進(jìn)行寫入操作
 for (int i = 0; i < 10; i++)
 {
  g_cArray[i] 
= 'a';
  Sleep(
1);
 }
 
// 釋放互斥對象
 ReleaseMutex(hMutex);
 
return 0;
}
UINT ThreadProc19(LPVOID pParam)
{
 
// 等待互斥對象通知
 WaitForSingleObject(hMutex, INFINITE);
 
// 對共享資源進(jìn)行寫入操作
 for (int i = 0; i < 10; i++)
 {
  g_cArray[
10 - i - 1= 'b';
  Sleep(
1);
 }
 
// 釋放互斥對象
 ReleaseMutex(hMutex);
 
return 0;
}
……
void CSample08View::OnMutex() 
{
 
// 創(chuàng)建互斥對象
 hMutex = CreateMutex(NULL, FALSE, NULL);
 
// 啟動線程
 AfxBeginThread(ThreadProc18, NULL);
 AfxBeginThread(ThreadProc19, NULL);
 
// 等待計算完畢
 Sleep(300);
 
// 報告計算結(jié)果
 CString sResult = CString(g_cArray);
 AfxMessageBox(sResult);
復(fù)制代碼

     互斥對象在MFC中通過CMutex類進(jìn)行表述。使用CMutex類的方法非常簡單,在構(gòu)造CMutex類對象的同時可以指明待查詢的互斥對象的名字,在構(gòu)造函數(shù)返回后即可訪問此互斥變量。CMutex類也是只含有構(gòu)造函數(shù)這唯一的成員函數(shù),當(dāng)完成對互斥對象保護(hù)資源的訪問后,可通過調(diào)用從父類CSyncObject繼承的UnLock()函數(shù)完成對互斥對象的釋放。CMutex類構(gòu)造函數(shù)原型為:
     CMutex( BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL );

    該類的適用范圍和實現(xiàn)原理與API方式創(chuàng)建的互斥內(nèi)核對象是完全類似的,但要簡潔的多,下面給出就是對前面的示例代碼經(jīng)CMutex類改寫后的程序?qū)崿F(xiàn)清單:

代碼
復(fù)制代碼
CMutex g_clsMutex(FALSE, NULL);     // MFC互斥類對象

UINT ThreadProc27(LPVOID pParam)
{
 g_clsMutex.Lock();                
// 等待互斥對象通知

 
for (int i = 0; i < 10; i++)      // 對共享資源進(jìn)行寫入操作
 {
  g_cArray[i] 
= 'a';
  Sleep(
1);
 }

 g_clsMutex.Unlock();              
// 釋放互斥對象
 return 0;
}
UINT ThreadProc28(LPVOID pParam)
{
 g_clsMutex.Lock();

 
for (int i = 0; i < 10; i++)
 {
  g_cArray[
10 - i - 1= 'b';
  Sleep(
1);
 }

 g_clsMutex.Unlock();
 
return 0;
}
……
void CSample08View::OnMutexMfc() 
{
 AfxBeginThread(ThreadProc27, NULL);
 AfxBeginThread(ThreadProc28, NULL);

 Sleep(
300);

 CString sResult 
= CString(g_cArray);
 AfxMessageBox(sResult);
}
復(fù)制代碼

Feedback

# re: MFC 多線程及線程同步  回復(fù)  更多評論   

2013-01-15 16:49 by tongy0
不錯。收了。

只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美国产精品专区| 国产欧美视频一区二区三区| 亚洲精品在线免费| 亚洲成色777777女色窝| 久久久国产亚洲精品| 欧美一区二区精品| 欧美一二区视频| 久久久精品国产99久久精品芒果| 亚洲一区二区黄| 欧美在线精品一区| 久久久免费观看视频| 国产视频在线观看一区二区三区| 国产伦理精品不卡| 在线成人国产| 在线一区二区三区四区五区| 香蕉视频成人在线观看| 久久综合久色欧美综合狠狠| 亚洲第一精品电影| 亚洲一区二区三区免费视频| 久久久久久91香蕉国产| 欧美午夜精品久久久久久浪潮| 国产精品亚洲成人| 亚洲人成啪啪网站| 久久99在线观看| 亚洲第一区在线观看| 亚洲一区二区三区在线观看视频 | 野花国产精品入口| 欧美在线播放一区| 欧美日韩亚洲视频| 亚洲大胆人体视频| 欧美一级午夜免费电影| 欧美成人高清视频| 亚洲无线观看| 欧美精品三区| 亚洲国产欧美久久| 久久精品国产一区二区三区免费看| 亚洲福利在线视频| 香蕉久久夜色| 国产精品久久久久高潮| 亚洲国产你懂的| 久久久久久电影| 亚洲视频在线看| 欧美激情四色 | 久久精品亚洲乱码伦伦中文| 欧美日韩一级大片网址| 亚洲黄色av一区| 男女精品视频| 欧美中文字幕| 国产乱码精品1区2区3区| 夜久久久久久| 91久久久久久国产精品| 欧美+日本+国产+在线a∨观看| 国产亚洲精品久久久久婷婷瑜伽| 亚洲免费影视| 一区二区三区色| 欧美午夜寂寞影院| 亚洲在线国产日韩欧美| 一本色道久久综合狠狠躁的推荐| 欧美激情亚洲国产| 日韩视频―中文字幕| 亚洲人午夜精品| 欧美日韩国产经典色站一区二区三区| 91久久精品www人人做人人爽| 美女免费视频一区| 麻豆精品一区二区av白丝在线| 狂野欧美性猛交xxxx巴西| 午夜精品久久久久久久99樱桃| 欧美不卡视频| 午夜久久久久久| 欧美欧美全黄| 欧美一区二区三区在线播放| 欧美专区亚洲专区| 亚洲九九精品| 午夜亚洲福利| 亚洲国产一区二区三区a毛片 | 久久久久久伊人| 国产三区二区一区久久| 久久福利视频导航| 久久久国产精品亚洲一区 | 国产亚洲精品一区二区| 久久av资源网站| 久久频这里精品99香蕉| 91久久一区二区| 一区二区三区四区五区精品| 国产精品一区免费视频| 久久综合久久综合这里只有精品 | 欧美高清视频| 亚洲天堂av电影| 欧美亚洲一区在线| 亚洲欧洲在线视频| 亚洲已满18点击进入久久| 精品99一区二区三区| 最新国产拍偷乱拍精品 | 亚洲第一二三四五区| 亚洲精品久久久蜜桃| 国产日韩精品在线观看| 亚洲国产mv| 国产午夜精品一区二区三区视频| 欧美顶级艳妇交换群宴| 国产精品免费区二区三区观看| 久久综合色天天久久综合图片| 欧美精品在线观看播放| 久久久久免费视频| 欧美日韩一区二区免费在线观看 | 91久久精品日日躁夜夜躁欧美| 国产精品亚洲а∨天堂免在线| 欧美福利精品| 国产视频欧美| 在线视频精品一| 另类激情亚洲| 亚洲福利专区| 久热爱精品视频线路一| 亚洲国产老妈| 亚洲美女视频在线观看| 久久综合久久综合九色| 亚洲国产精品v| 久久精品日韩欧美| 99在线观看免费视频精品观看| 欧美性猛片xxxx免费看久爱| 久久亚洲电影| 性感少妇一区| 亚洲一区二区三区午夜| 美日韩精品免费| 久久香蕉国产线看观看av| 国产精品久久久999| 亚洲欧洲综合另类| 在线看片日韩| 久久精品国产亚洲精品| 久久国产88| 国产精品久久久久久久久久久久久 | 亚洲欧美精品伊人久久| 在线亚洲欧美专区二区| 欧美激情1区| 欧美激情一区二区三区在线视频观看 | 欧美日韩国产综合新一区| 亚洲国产成人av| 日韩一二在线观看| 欧美日韩精品中文字幕| 亚洲美女电影在线| 亚洲一本大道在线| 国产精品白丝jk黑袜喷水| 亚洲天堂网在线观看| 欧美一级理论片| 国产一区二区黄色| 久久精品中文字幕一区| 美女精品视频一区| 亚洲国产成人在线| 欧美精品 国产精品| 日韩一级大片在线| 午夜在线一区二区| 黄色亚洲免费| 欧美国产精品va在线观看| 最新中文字幕一区二区三区| 日韩视频中文字幕| 欧美亚洲成人网| 欧美一级久久久久久久大片| 久久影院午夜论| 亚洲国产一区二区三区青草影视| 欧美精品久久久久久久久久| 亚洲精品视频免费在线观看| 亚洲香蕉网站| 亚洲一区3d动漫同人无遮挡| 国产日韩专区| 亚洲综合色网站| 美国成人毛片| 一本到12不卡视频在线dvd| 国产精品vvv| 欧美在线视频免费| 亚洲国产裸拍裸体视频在线观看乱了中文 | 欧美激情视频一区二区三区在线播放 | 久久成人亚洲| 亚洲日本电影在线| 欧美专区亚洲专区| 亚洲精品国产日韩| 国产日韩欧美精品| 欧美日韩国产在线播放网站| 久久精品在线观看| 亚洲调教视频在线观看| 亚洲黄色免费电影| 久久精品视频99| 一区二区三区高清| 韩国av一区二区三区| 欧美日韩一区三区四区| 久久久99精品免费观看不卡| 一区二区三区成人精品| 欧美sm重口味系列视频在线观看| 亚洲一区免费视频| 亚洲精品美女在线观看| 国内激情久久| 国产精品户外野外| 欧美刺激午夜性久久久久久久| 亚洲自拍16p| 日韩一区二区免费看| 欧美激情精品久久久六区热门 | 9l视频自拍蝌蚪9l视频成人| 欧美成人激情在线| 久久亚洲精品网站| 午夜久久tv| 亚洲欧美网站| 中文网丁香综合网|