在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<abbr id="27omo"></abbr>

<menu id="27omo"><dl id="27omo"></dl></menu>
    • <label id="27omo"><tt id="27omo"></tt></label>

      新聞中心

      EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > Windows CE 進(jìn)程、線程和內(nèi)存管理(二)

      Windows CE 進(jìn)程、線程和內(nèi)存管理(二)

      作者: 時(shí)間:2006-12-09 來(lái)源:網(wǎng)絡(luò) 收藏
      二、同步

        在多數(shù)情況下,線程之間難免要相互通信、相互協(xié)調(diào)才能完成任務(wù)。比如,當(dāng)有多個(gè)線程共同訪問(wèn)同一個(gè)資源時(shí),就必須保證一個(gè)線程正讀取這個(gè)資源數(shù)據(jù)的時(shí)候,其它線程不能夠修改它。這就需要線程之間相互通信,了解對(duì)方的行為。再有當(dāng)一個(gè)線程要準(zhǔn)備執(zhí)行下一個(gè)任務(wù)之前,它必須等待另一個(gè)線程終止才能運(yùn)行,這也需要彼此相互通信。實(shí)際開(kāi)發(fā)過(guò)程中,線程間需要同步的情況非常多。Windows CE.NET給我們提供了很多的同步機(jī)制,熟練的掌握這些機(jī)制并合理運(yùn)用會(huì)使線程之間的同步更合理、更高效。進(jìn)程間的通信機(jī)制在下一篇文章中講解。

        Windows CE.NET具有兩種運(yùn)行模式:用戶模式和內(nèi)核模式。并且允許一個(gè)運(yùn)行于用戶模式的應(yīng)用程序隨時(shí)切換為內(nèi)核模式,或切換回來(lái)。線程同步的有些解決辦法運(yùn)行在用戶模式,有些運(yùn)行在內(nèi)核模式?!禬indows核心編程》上說(shuō)從用戶模式切換到內(nèi)核模式再切換回來(lái)至少要1000個(gè)CPU周期。我查看過(guò)CE下API函數(shù)SetKMode的源碼,這個(gè)函數(shù)用于在兩種模式間切換,改變模式只需修改一些標(biāo)志,至于需要多少個(gè)CPU周期很難確定。但至少可以肯定來(lái)回切換是需要一定時(shí)間的。所以在選擇同步機(jī)制上應(yīng)該優(yōu)先考慮運(yùn)行在用戶模式的同步解決辦法。

      1、互鎖函數(shù)

        互鎖函數(shù)運(yùn)行在用戶模式。它能保證當(dāng)一個(gè)線程訪問(wèn)一個(gè)變量時(shí),其它線程無(wú)法訪問(wèn)此變量,以確保變量值的唯一性。這種訪問(wèn)方式被稱為原子訪問(wèn)。互鎖函數(shù)及其功能見(jiàn)如下列表:

      函數(shù)參數(shù)和功能
      InterlockedIncrement參數(shù)為PLONG類型。此函數(shù)使一個(gè)LONG變量增1
      InterlockedDecrement參數(shù)為PLONG類型。此函數(shù)使一個(gè)LONG變量減1
      InterlockedExchangeAdd參數(shù)1為PLONG類型,參數(shù)2為L(zhǎng)ONG類型。此函數(shù)將參數(shù)2賦給參數(shù)1指向的值
      InterlockedExchange參數(shù)1為PLONG類型,參數(shù)2為L(zhǎng)ONG類型。此函數(shù)將參數(shù)2的值賦給參數(shù)1指向的值
      InterlockedExchangePointer參數(shù)為PVOID* 類型,參數(shù)2為PVOID類型。此函數(shù)功能同上。具體參見(jiàn)幫助
      InterlockedCompareExchange參數(shù)1為PLONG類型,參數(shù)2為L(zhǎng)ONG類型,參數(shù)3為L(zhǎng)ONG類型。此函數(shù)將參數(shù)1指向的值與參數(shù)3比較,相同則把參數(shù)2的值賦給參數(shù)1指向的值。不相同則不變
      InterlockedCompareExchangePointer參數(shù)1為PVOID* 類型,參數(shù)2為PVOID類型,參數(shù)3為PVOID。此函數(shù)功能同上。具體參見(jiàn)幫助

      2、臨界區(qū)

        臨界區(qū)對(duì)象運(yùn)行在用戶模式。它能保證在臨界區(qū)內(nèi)所有被訪問(wèn)的資源不被其它線程訪問(wèn),直到當(dāng)前線程執(zhí)行完臨界區(qū)代碼。除了API外,MFC也對(duì)臨界區(qū)函數(shù)進(jìn)行了封裝。臨界區(qū)相關(guān)函數(shù):

      void InitializeCriticalSection ( LPCRITICAL_SECTION );
      void EnterCriticalSection ( LPCRITICAL_SECTION );
      void LeaveCriticalSection ( LPCRITICAL_SECTION );
      void DeleteCriticalSection ( LPCRITICAL_SECTION );

      舉例如下:

      void CriticalSectionExample (void)
      {
      CRITICAL_SECTION csMyCriticalSection;
      InitializeCriticalSection (csMyCriticalSection); ///初始化臨界區(qū)變量

      __try
      {
      EnterCriticalSection (csMyCriticalSection); ///開(kāi)始保護(hù)機(jī)制
      ///此處編寫代碼
      }

      __finally ///異常處理,無(wú)論是否異常都執(zhí)行此段代碼
      {
      LeaveCriticalSection (csMyCriticalSection); ///撤銷保護(hù)機(jī)制
      }
      }

      MFC類使用更簡(jiǎn)單:

      CCriticalSection cs;

      cs.Lock();

      ///編寫代碼

      cs.Unlock();

        使用臨界區(qū)要注意的是避免死鎖。當(dāng)有兩個(gè)線程,每個(gè)線程都有臨界區(qū),而且臨界區(qū)保護(hù)的資源有相同的時(shí)候,這時(shí)就要在編寫代碼時(shí)多加考慮。

      3、事件對(duì)象

        事件對(duì)象運(yùn)行在內(nèi)核模式。與用戶模式不同,內(nèi)核模式下線程利用等待函數(shù)來(lái)等待所需要的事件、信號(hào),這個(gè)等待過(guò)程由操作系統(tǒng)內(nèi)核來(lái)完成,而線程處于睡眠狀態(tài),當(dāng)接收到信號(hào)后,內(nèi)核恢復(fù)線程的運(yùn)行。內(nèi)核模式的優(yōu)點(diǎn)是線程在等待過(guò)程中并不浪費(fèi)CPU時(shí)間,缺點(diǎn)是從用戶模式切換到內(nèi)核模式需要一定的時(shí)間,而且還要切換回來(lái)。在講解事件對(duì)象前應(yīng)該先談?wù)劦却瘮?shù)。等待函數(shù)有四個(gè)。具體參數(shù)和功能見(jiàn)下表:

      函數(shù)參數(shù)和功能
      WaitForSingleObject參數(shù)1為HANDLE類型,參數(shù)2為DWORD類型。此函數(shù)等待參數(shù)1標(biāo)識(shí)的事件,等待時(shí)間為參數(shù)2的值,單位ms。如果不超時(shí),當(dāng)事件成為有信號(hào)狀態(tài)時(shí),線程喚醒繼續(xù)運(yùn)行。
      WaitForMultipleObjects參數(shù)1為DWORD類型,參數(shù)2為HANDLE * 類型,參數(shù)3為BOOL類型,參數(shù)4為DWORD類型。此函數(shù)等待參數(shù)2指向的數(shù)組中包含的所有事件。如果不超時(shí),當(dāng)參數(shù)3為FALSE時(shí),只要有一個(gè)事件處于有信號(hào)狀態(tài),函數(shù)就返回這個(gè)事件的索引。參數(shù)3為TRUE時(shí),等待所有事件都處于有信號(hào)狀態(tài)時(shí)才返回。
      MsgWaitForMultipleObjects參數(shù)1為DWORD類型,參數(shù)2為L(zhǎng)PHANDLE類型,參數(shù)3為BOOL類型,參數(shù)4為DWORD類型,參數(shù)5為DWORD類型。此函數(shù)功能上同WaitForMultipleObjects函數(shù)相似,只是多了一個(gè)喚醒掩碼。喚醒掩碼都是和消息有關(guān)的。此函數(shù)不但能夠?yàn)槭录却€能為特定的消息等待。其實(shí)這個(gè)函數(shù)就是專為等待消息而定義的。
      MsgWaitForMultipleObjectsEx參數(shù)1為DWORD類型,參數(shù)2為L(zhǎng)PHANDLE類型,參數(shù)3為DWORD類型,參數(shù)4為DWORD類型,參數(shù)5為DWORD類型。此函數(shù)是MsgWaitForMultipleObjects函數(shù)的擴(kuò)展。將原來(lái)函數(shù)的參數(shù)3除掉,添加參數(shù)5為標(biāo)志。標(biāo)志有兩個(gè)值:0或MWMO_INPUTAVAILABLE。

      如果一個(gè)線程既要執(zhí)行大量任務(wù)同時(shí)又要響應(yīng)用戶的按鍵消息,這兩個(gè)專用于等待消息的函數(shù)將非常有用。

      和事件有關(guān)的函數(shù)有:

      HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,
      BOOL bManualReset,
      BOOL bInitialState,
      LPTSTR lpName);

      BOOL SetEvent(HANDLE hEvent );
      BOOL PulseEvent(HANDLE hEvent);
      BOOL ResetEvent(HANDLE hEvent);

      HANDLE OpenEvent(DWORD dwDesiredAccess,
      BOOL bInheritHandle,
      LPCTSTR lpName );

        事件對(duì)象是最常用的內(nèi)核模式同步方法。它包含一個(gè)使用計(jì)數(shù)和兩個(gè)BOOL變量。其中一個(gè)BOOL變量指定這個(gè)事件對(duì)象是自動(dòng)重置還是手工重置。另一個(gè)BOOL變量指定當(dāng)前事件對(duì)象處于有信號(hào)狀態(tài)還是無(wú)信號(hào)狀態(tài)。

        函數(shù)CreateEvent創(chuàng)建一個(gè)事件對(duì)象,參數(shù)1必須為NULL,參數(shù)2指定是否手工重新設(shè)置事件對(duì)象的狀態(tài)。如果為FALSE,當(dāng)?shù)却瘮?shù)接到信號(hào)并返回后此事件對(duì)象被自動(dòng)置為無(wú)信號(hào)狀態(tài)。這時(shí)等待此事件對(duì)象的其它線程就不會(huì)被喚醒,因?yàn)槭录?duì)象已經(jīng)被置為無(wú)信號(hào)狀態(tài)。如果參數(shù)2設(shè)置為TRUE,當(dāng)?shù)却瘮?shù)接到信號(hào)并返回后事件對(duì)象不會(huì)被自動(dòng)置于無(wú)信號(hào)狀態(tài),其它等待此事件對(duì)象的線程都能夠被喚醒。用ResetEvent函數(shù)可以手工將事件對(duì)象置為無(wú)信號(hào)狀態(tài)。相反SetEvent函數(shù)將事件對(duì)象置為有信號(hào)狀態(tài)。PulseEvent函數(shù)將事件對(duì)象置為有信號(hào)狀態(tài),然后立即置為無(wú)信號(hào)狀態(tài),在實(shí)際開(kāi)發(fā)中這個(gè)函數(shù)很少使用。OpenEvent函數(shù)打開(kāi)已經(jīng)創(chuàng)建的事件對(duì)象,一般用于不同進(jìn)程內(nèi)的線程同步。在調(diào)用CreateEvent創(chuàng)建一個(gè)事件對(duì)象時(shí),傳遞一個(gè)名字給參數(shù)4,這樣在其它進(jìn)程中的線程就可以調(diào)用OpenEvent函數(shù)并指定事件對(duì)象的名字,來(lái)訪問(wèn)這個(gè)事件對(duì)象。

      4、互斥對(duì)象

        互斥對(duì)象運(yùn)行在內(nèi)核模式。它的行為特性同臨界區(qū)非常相似,在一個(gè)線程訪問(wèn)某個(gè)共享資源時(shí),它能夠保證其它線程不能訪問(wèn)這個(gè)資源。不同的是,互斥對(duì)象運(yùn)行在內(nèi)核模式,從時(shí)間上比臨界區(qū)要慢。由于內(nèi)核對(duì)象具有全局性,不同的進(jìn)程都能夠訪問(wèn),這樣利用互斥對(duì)象就可以讓不同的進(jìn)程中的線程互斥訪問(wèn)一個(gè)共享資源。而臨界區(qū)只能在一個(gè)進(jìn)程內(nèi)有效。

      和互斥相關(guān)的函數(shù)有:

      HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,
      BOOL bInitialOwner,
      LPCTSTR lpName);

      BOOL ReleaseMutex(HANDLE hMutex);

        互斥對(duì)象包含一個(gè)引用計(jì)數(shù),一個(gè)線程ID和一個(gè)遞歸計(jì)數(shù)。引用計(jì)數(shù)是所有內(nèi)核對(duì)象都含有的。線程ID表示哪個(gè)線程正在使用互斥資源,當(dāng)ID為0時(shí),互斥對(duì)象發(fā)出信號(hào)。遞歸計(jì)數(shù)用于一個(gè)線程多次等待同一個(gè)互斥對(duì)象。函數(shù)CreateMutex創(chuàng)建一個(gè)互斥對(duì)象,參數(shù)1必須設(shè)置為NULL,參數(shù)2如果設(shè)置為FALSE,表示當(dāng)前線程并不占有互斥資源,互斥對(duì)象的線程ID和遞歸計(jì)數(shù)都被設(shè)置為0,互斥對(duì)象處于有信號(hào)狀態(tài)。如果設(shè)置為TRUE,表示當(dāng)前線程將占有互斥資源,互斥對(duì)象的線程ID被設(shè)置為當(dāng)前線程ID,遞歸計(jì)數(shù)被設(shè)置為1,互斥對(duì)象處于無(wú)信號(hào)狀態(tài)。當(dāng)調(diào)用等待函數(shù)時(shí),等待函數(shù)檢驗(yàn)互斥對(duì)象的線程ID是否為0,如果為0,說(shuō)明當(dāng)前沒(méi)有線程訪問(wèn)互斥資源,內(nèi)核將線程喚醒,并且將互斥對(duì)象的遞歸計(jì)數(shù)加1。當(dāng)一個(gè)線程被喚醒后,必須調(diào)用函數(shù)ReleaseMutex將互斥對(duì)象的遞歸計(jì)數(shù)減1。如果一個(gè)線程多次調(diào)用等待函數(shù),就必須以同樣的次數(shù)調(diào)用ReleaseMutex函數(shù)。與其它Windows不同的是,和互斥相關(guān)的函數(shù)中沒(méi)有OpenMutex函數(shù)。要在不同進(jìn)程中訪問(wèn)同一互斥對(duì)象,調(diào)用CreateMutex函數(shù),參數(shù)傳遞互斥對(duì)象的名稱,返回這個(gè)互斥對(duì)象的句柄。

      5、信標(biāo)對(duì)象

        信標(biāo)對(duì)象,也叫信號(hào)燈,用于限制資源訪問(wèn)數(shù)量,他包含一個(gè)引用計(jì)數(shù),一個(gè)當(dāng)前可用資源數(shù),一個(gè)最大可用資源數(shù)。如果當(dāng)前可用資源數(shù)大于0,信標(biāo)對(duì)象處于有信號(hào)狀態(tài)。當(dāng)可用資源數(shù)等于0,信標(biāo)對(duì)象處于無(wú)信號(hào)狀態(tài)。

      和信標(biāo)對(duì)象相關(guān)的函數(shù):

      HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
      LONG lInitialCount,
      LONG lMaximumCount,
      LPCTSTR lpName);

      BOOL ReleaseSemaphore(HANDLE hSemaphore,
      LONG lReleaseCount,
      LPLONG lpPreviousCount);

        函數(shù)CreateSemaphore的參數(shù)1為NULL,參數(shù)2為當(dāng)前可用資源初始值,參數(shù)3為最大可用資源數(shù),參數(shù)4為名字。當(dāng)參數(shù)2的值等于0時(shí),信標(biāo)對(duì)象處于無(wú)信號(hào)狀態(tài),這時(shí)內(nèi)核將調(diào)用等待函數(shù)的線程置于睡眠狀態(tài),如果參數(shù)2的值大于0,信標(biāo)對(duì)象處于有信號(hào)狀態(tài),這時(shí)內(nèi)核將調(diào)用等待函數(shù)的線程置于運(yùn)行狀態(tài),并將信標(biāo)對(duì)象的當(dāng)前可用資源數(shù)減1。函數(shù)ReleaseSemaphore的參數(shù)1為信標(biāo)對(duì)象的句柄,參數(shù)2為要釋放的資源數(shù),參數(shù)3返回原來(lái)可用資源數(shù),調(diào)用此函數(shù)將當(dāng)前可用資源數(shù)加上參數(shù)2的值。當(dāng)一個(gè)線程訪問(wèn)完可用資源后,應(yīng)該調(diào)用ReleaseSemaphore函數(shù)使當(dāng)前可用資源數(shù)遞增。要在不同進(jìn)程中訪問(wèn)同一信標(biāo)對(duì)象,調(diào)用CreateSemaphore函數(shù)并傳遞信標(biāo)對(duì)象的名稱,得到已經(jīng)在其它進(jìn)程創(chuàng)建的信標(biāo)對(duì)象的句柄。CE下沒(méi)有OpenSemaphore函數(shù)。另外我還要說(shuō)明一點(diǎn),等待函數(shù)默認(rèn)將信標(biāo)對(duì)象的當(dāng)前可用資源數(shù)減1,但線程可能一次使用多個(gè)資源,這就可能出現(xiàn)問(wèn)題了。為避免問(wèn)題出現(xiàn),應(yīng)該遵守一個(gè)線程只使用一個(gè)資源的原則。

      6、消息隊(duì)列

        Windows CE.NET允許一個(gè)應(yīng)用程序或驅(qū)動(dòng)程序創(chuàng)建自己的消息隊(duì)列。消息隊(duì)列既可以作為在線程之間傳遞數(shù)據(jù)的工具,也可以作為線程之間同步的工具。它的優(yōu)點(diǎn)是需要很小的內(nèi)存,一般只用于點(diǎn)到點(diǎn)的通信。

      和消息隊(duì)列相關(guān)的函數(shù):

      HANDLE WINAPI CreateMsgQueue(LPCWSTR lpszName,
      LPMSGQUEUEOPTIONS lpOptions);

      BOOL WINAPI CloseMsgQueue(HANDLE hMsgQ);
      BOOL GetMsgQueueInfo(HANDLE hMsgQ,
      LPMSGQUEUEINFO lpInfo);

      HANDLE WINAPI OpenMsgQueue(HANDLE hSrcProc,
      HANDLE hMsgQ,
      LPMSGQUEUEOPTIONS lpOptions);

      BOOL ReadMsgQueue(HANDLE hMsgQ,
      LPVOID lpBuffer,
      DWORD cbBufferSize,
      LPDWORD lpNumberOfBytesRead,
      DWORD dwTimeout,
      DWORD *pdwFlags);

      BOOL WINAPI WriteMsgQueue(HANDLE hMsgQ,
      LPVOID lpBuffer,
      DWORD cbDataSize,
      DWORD dwTimeout,
      DWORD dwFlags);

        使用CreateMsgQueue函數(shù)創(chuàng)建一個(gè)消息隊(duì)列,傳遞一個(gè)MSGQUEUEOPTIONS結(jié)構(gòu)指針。在這個(gè)結(jié)構(gòu)中設(shè)置標(biāo)志(允許隊(duì)列緩沖區(qū)動(dòng)態(tài)改變大小,允許直接讀或者寫操作而不管之前是否有過(guò)寫操作或讀操作)、隊(duì)列允許的最大消息數(shù)、隊(duì)列屬性(只讀或者只寫)。使用WriteMsgQueue函數(shù)把一個(gè)消息寫入到消息隊(duì)列中。傳遞一個(gè)消息隊(duì)列的緩沖區(qū)、消息數(shù)據(jù)的大小、寫入緩沖區(qū)的超時(shí)值、標(biāo)志。使用ReadMsgQueue函數(shù)把一個(gè)消息從消息隊(duì)列中讀出。使用CloseMsgQueue函數(shù)關(guān)閉消息隊(duì)列緩沖區(qū)。使用OpenMsgQueue函數(shù)能夠打開(kāi)其它進(jìn)程中創(chuàng)建的消息隊(duì)列。另外可以用等待函數(shù)等待消息隊(duì)列的變化。當(dāng)消息隊(duì)列由沒(méi)有消息到有消息時(shí),或由滿消息到不滿消息時(shí)喚醒調(diào)用等待函數(shù)的線程。關(guān)于消息隊(duì)列我并沒(méi)有實(shí)驗(yàn)過(guò),MSDN上有幾個(gè)簡(jiǎn)單的例子。


      評(píng)論


      相關(guān)推薦

      技術(shù)專區(qū)

      關(guān)閉