天天看點

音視訊(Windows同步機制 )

同步的意思是,保證一個程式在被不适宜的切換時,不會出現問題。

    對Window3.1來講,雖然有多任務,但是沒有同步基層。因為這些多任務的協作是通過調用API函數,比如(GetMessage和PeekMessage)來實作。如果一個程式調用了GetMessage或PeekMessage,則意思就是說,我現在處于可中斷狀态。

    Win32程式沒有這樣的協作多任務,他們必須做好随時被CPU切換掉的準備。一個真正的Win32程式不應該耗盡CPU時間去等待某些事情的發生。

    Win32API有四個主要的同步對象:(1)Event 事件;(2)Semaphore 信号量;(3)Mutexes 互斥;(4)Critical Section 臨界區。

    除Critical Setion外,其餘是系統全局對象,并且與不同程序及相同程序中的線程一起工作,這樣同步機制也可以用于程序同步。

    1。事件(Event)

    這是同步對象的一種類型類型,正如其名字含義,在這個中心周圍是一些發生在另一個程序或線程中的特殊活動。當你希望線程暫時挂起時,不會消耗CPU的工作周期。事件類似我們常用的消息概念。如果我們剖析消息的核心,肯定能發現,它就是用事件來實作的。這裡解釋一下事件與消息的差別:

    事件實際上就是消息的到達,也就是說一個消息經過一系列的過程到達了,它就會觸發一個事件處理器,事件處理器就會調用你寫的事件處理函數。而消息就是發消息給系統,系統會有消息隊列。然後系統根據一定的排程會取到等待處理的消息(當然有可能丢失)來調用消息相應函數。雖然效果一樣,但是事件系統顯然跟安全,因為不會丢失消息。

    程式可用CreateEvent或OpenEvent對事件獲得一個句柄:

    HANDLE CreateEvent (

<b>                    );</b>

     HANDLE OpenEvent(

    函數參數和傳回值解釋請參考MSDN,以下相同。

    然後,該程式再調用WaitForSingleObject,標明事件句柄和等待逾時時間。那麼線程就會被挂起,一直到其他線程調用下面API函數,給出事件有關信号後才再次被激活。

    BOOL SetEvent(

<b>                );</b>

    BOOL PulseEvent(

    比如,當一個線程要使用另一個線程的排序結果時,你或許希望去使用一個事件。比較糟糕的方法是執行這個線程,并在結束時設定全局變量标志,另一個線程循環檢查這個标志是否已設定,這就浪費很多CPU時間。用事件作同樣的事情則很簡單,排序線程在結束時産生一個事件,其他線程調用WaitForSingleObject。這就使得線程被挂起。當排序線程完成時,調用SetEvent喚醒另一個線程繼續執行。

    除了WaitForSingleObject外,還有WaitForMultipleObjects,允許一個線程被挂起,直到滿足多個Event條件。

    舉例說明。

    音視訊通信過程中,我們用一個TCP Socket,m_hDataSock接收資料,在沒有資料到達時,接收線程會被挂起,直到有資料到達或者Socket逾時,來進行相應處理,示例方法如下:

UINT RecvDataThread(LPVOID pPara)

{

     WSAEVENT  =  WSACreateEvent();

     WSAEventSelect(m_hDataSock,m_hEvent,FD_READ | FD_CLOSE);

     while(!m_bThreadEnd)

     {

          DWORD dwWait = WSAWaitForMultipleEvents(1,&amp;m_hEvent,FALSE,18000,FALSE);

          if (WSA_WAIT_TIMEOUT == dwWait)

          {

              //逾時處理

               break;

          }

          if(WAIT_OBJECT_0 == dwWait)

               WSANETWORKEVENTS netEvents;

               if(SOCKET_ERROR == WSAEnumNetworkEvents(m_hDataSock,m_hEvent,&amp;netEvents))

               {

                    continue;

               }

               if((netEvents.lNetworkEvents &amp; FD_READ) &amp;&amp; (0 == netEvents.iErrorCode[FD_READ_BIT]))

                    //接收資料

               else if(netEvents.lNetworkEvents &amp; FD_CLOSE)

                      //處理通道關閉

                        break;

     }

     WSACloseEvent(m_hEvent);

     _endthreadex(0);

     return 0;

}

    2。信号量

    當需要限制通路特殊資源或限制一段代碼到某些線程是,Semaphores非常有用。比如說,一樣資源有十個,當你需要用時,已經被其他十個人占用了。這樣就必須等待,直到有人不用了,歸還了資源。

    在Win32程式設計中獲得Semaphores就好像獲得該資源的一次控制。

    為了利用Semaphores,一個線程調用CreateSemaphore去獲得一個HANDLE給Semaphores。也就是将Semaphores與資源綁定,并初始化該Semaphores,并傳回該Semaphores的句柄。

    函數原型如下:

    HANDLE CreateSemaphore(

<b>                      );</b>

    如果Semaphores在其他程序中建立,可以用OpenSemaphore去擷取其句柄。

    HANDLE OpenSemaphore(

                      );

    接下來當然是利用等待函數來阻塞線程。如果這個Semaphore計數大于0,這等待功能隻是簡單處理Semaphores的使用數,線程繼續執行,換句話說,如果Semaphores使用數超出最大值,則等待線程被挂起。當然也可以利用ReleaseSemaphore來釋放資源。

    BOOL ReleaseSemaphore(

<b>                  );</b>

    也就是用信号量這個對象來管理某個資源的配置設定與回收。

    3。互斥(Mutexes)

    Mutex是“mutual exclusion”的縮寫。希望一次隻有一個線程去通路一個資源或一段代碼時可以使用互斥。使用方法與信号量類似。建立和釋放Mutex的函數原型如下:

    HANDLE CreateMutex(

    BOOL ReleaseMutex(

    可以将使用方法封裝成類,如下:

    class CMutex  

    {

        public:

             CMutex(HANDLE hMutex){m_hMutex = hMutex; WaitForSingleObject(m_hMutex,INFINITE);}

             virtual ~CMutex(){ReleaseMutex(m_hMutex);}

        private:

             HANDLE m_hMutex;

    };

    使用的時候首先聲明一個HANDLE  m_hMutex;調用接口建立Mutex,m_hMutex = CreateMutex(NULL,FALSE,NULL);然後再任何需要互斥的代碼前構造這樣一個類就可以了。比如,CMutex mutex(m_hMutex);

    4。臨界區(Critical Sections)

    臨界段相當于一個微型的互斥,隻能被同一個程序中的線程使用。臨界區是為了防止多線程同時執行一段代碼。相對其他同步機而言,臨界區相對簡單和易用。一般先聲明一個CRITICAL_SECTION類型的全局變量,然後調用下面三個函數來使用它。

    VOID InitializeCriticalSection(

    VOID EnterCriticalSection(

    VOID LeaveCriticalSection(

    5。WaitForSingleObject/WaitForMultipleObjects函數

    其實,線程同步,除了上面四種方法外,還可以使用WaitForSingleObject/WaitForMultipleObjects函數。等待的HANDLE可以是線程的句柄,檔案的句柄等。

本文轉自 fanxiaojun 51CTO部落格,原文連結:http://blog.51cto.com/2343338/1060567,如需轉載請自行聯系原作者

繼續閱讀