原文地址:http://blog.csdn.net/temotemo/article/details/7609642
1、臨界區與臨界資源相關概念
臨界區
不論是硬件臨界資源,還是軟件臨界資源,多個進程必須互斥地對它進行訪問。每個進程中訪問臨界資源的那段代碼稱爲臨界區(Critical Section)。
每個進程中訪問臨界資源的那段程序稱爲臨界區(Critical Section)(臨界資源是一次僅允許一個進程使用的共享資源)。每次只准許一個進程進入臨界區,進入後不允許其他進程進入。不論是硬件臨界資源,還是軟件臨界資源,多個進程必須互斥地對它進行訪問。
多個進程中涉及到同一個臨界資源的臨界區稱爲相關臨界區。
進程進入臨界區的調度原則是:
①如果有若干進程要求進入空閒的臨界區,一次僅允許一個進程進入。
②任何時候,處於臨界區內的進程不可多於一個。如已有進程進入自己的臨界區,則其它所有試圖進入臨界區的進程必須等待。
③進入臨界區的進程要在有限時間內退出,以便其它進程能及時進入自己的臨界區。
④如果進程不能進入自己的臨界區,則應讓出CPU,避免進程出現“忙等”現象。
如果有多個線程試圖同時訪問臨界區,那麼在有一個線程進入後其他所有試圖訪問此臨界區的線程將被掛起,並一直持續到進入臨界區的線程離開。臨界區在被釋放後,其他線程可以繼續搶佔,並以此達到用原子方式操作共享資源的目的。
臨界區在使用時以CRITICAL_SECTION結構對象保護共享資源,並分別用EnterCriticalSection()和LeaveCriticalSection()函數去標識和釋放一個臨界區。所用到的CRITICAL_SECTION結構對象必須經過InitializeCriticalSection()的初始化後才能使用,而且必須確保所有線程中的任何試圖訪問此共享資源的代碼都處在此臨界區的保護之下。否則臨界區將不會起到應有的作用,共享資源依然有被破壞的可能。
2、WebRTC中臨界區和臨界資源
在WebRTC源碼裏,對線程互斥訪問臨界資源設計一個良好的面向對象的實現方法。
大體框圖:
圖示說明:
(1)CriticalSectionWrapper類用於封裝臨界區的操作,包括windows平臺和非windows平臺的;直接使用CriticalSectionWrapper定義臨界區;
(2)CriticalSectionWrapper類是CriticalSectionWindows和CriticalSectionPosix的父類;CriticalSectionWindows表示Windows平臺下使用Windows API定義臨界區,同理CriticalSectionPosix表示非Windows平臺下使用Posix定義臨界區;
(3)CriticalSectionScoped類的構造函數爲CriticalSectionScoped(CriticalSectionWrapper& critsec),CriticalSectionWrapper的引用作爲參數,(注意:CriticalSectionWrapper構造函數返回的並不是它本身,而是根據平臺選擇返回它的派生類對象,返回CriticalSectionWindows對象或者CriticalSectionPosix對象,以此達到CriticalSectionWrapper封裝的目的)並且在定義CriticalSectionScoped的同時進入臨界區;CriticalSectionScoped析構函數離開臨界區;
定義CriticalSectionWrapper類和CriticalSectionScoped類:(critical_section_wrapper.h)
- //=========critical_section_wrapper.h
- #ifndef CRITICAL_SECTION_WRAPPER_H
- #define CRITICAL_SECTION_WRAPPER_H
- namespace webrtc {
- class CriticalSectionWrapper
- {
- public:
- // Factory method, constructor disabled
- static CriticalSectionWrapper* CreateCriticalSection();//工廠方法,創建臨界區,返回指針
- virtual ~CriticalSectionWrapper() {}
- // Tries to grab lock, beginning of a critical section. Will wait for the
- // lock to become available if the grab failed.
- virtual void Enter() = 0;
- // Returns a grabbed lock, end of critical section.
- virtual void Leave() = 0;
- };
- // RAII extension of the critical section. Prevents Enter/Leave missmatches and
- // provides more compact critical section syntax.
- class CriticalSectionScoped
- {
- public:
- CriticalSectionScoped(CriticalSectionWrapper& critsec) //構造函數,進入臨界區
- :
- _ptrCritSec(&critsec)
- {
- _ptrCritSec->Enter();
- }
- ~CriticalSectionScoped() //析構函數,保證離開臨界區
- {
- if (_ptrCritSec)
- {
- Leave();
- }
- }
- private:
- void Leave()
- {
- _ptrCritSec->Leave();
- _ptrCritSec = 0;
- }
- CriticalSectionWrapper* _ptrCritSec;
- };
- } // namespace
- #endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_
CriticalSectionWrapper類實現:(critical_section.cpp)
- //=========== critical_section.cpp
- #if defined(_WIN32)
- #include <windows.h>
- #include "critical_section_windows.h" //使用Windows平臺API
- #else
- #include "critical_section_posix.h" //使用posix
- #endif
- namespace webrtc {
- CriticalSectionWrapper* CriticalSectionWrapper::CreateCriticalSection()
- {
- #ifdef _WIN32
- return new CriticalSectionWindows();//Windows平臺,返回CriticalSectionWindows對象
- #else
- return new CriticalSectionPosix(); //非Windows平臺,返回CriticalSectionPosix對象
- #endif
- }
- } // namespace webrt<strong>
- </strong>
Windows平臺下臨界區操作CriticalSectionWindows API 定義頭文件(critical_section_windows.h)
- //============== critical_section_windows.h
- #ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_
- #define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_
- //#include "typedefs.h"
- #include "critical_section_wrapper.h"
- #include <windows.h> //使用Windows平臺API
- namespace webrtc {
- class CriticalSectionWindows : public CriticalSectionWrapper
- {
- public:
- CriticalSectionWindows();
- virtual ~CriticalSectionWindows();
- virtual void Enter();
- virtual void Leave();
- private:
- CRITICAL_SECTION crit;
- //friend class ConditionVariableWindows;
- };
- } // namespace webrtc
- #endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_
Windows平臺下臨界區操作CriticalSectionWindows類 API 實現文件(critical_section_windows.cpp)
- //============= critical_section_windows.cpp
- #include "critical_section_windows.h"
- namespace webrtc {
- CriticalSectionWindows::CriticalSectionWindows()
- {
- InitializeCriticalSection(&crit); //構造函數初始化臨界區
- }
- CriticalSectionWindows::~CriticalSectionWindows()
- {
- DeleteCriticalSection(&crit);//析構函數刪除臨界區,利用類來管理資源的思想,Effective C++思想
- }
- void
- CriticalSectionWindows::Enter()
- {
- EnterCriticalSection(&crit); //進入臨界資源
- }
- void
- CriticalSectionWindows::Leave()
- {
- LeaveCriticalSection(&crit); //離開臨界資源
- }
- } // namespace webrtc<strong>
- </strong>
非Windows平臺下臨界區操作CriticalSectionPosix API 定義頭文件(critical_section_posix.h)
- #ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_
- #define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_
- //非Windows平臺使用Posix的臨界資源
- #include "critical_section_wrapper.h"
- #include <pthread.h> //使用Posix
- namespace webrtc {
- class CriticalSectionPosix : public CriticalSectionWrapper
- {
- public:
- CriticalSectionPosix();
- virtual ~CriticalSectionPosix();
- virtual void Enter();
- virtual void Leave();
- private:
- pthread_mutex_t _mutex;
- //friend class ConditionVariablePosix;
- };
- } // namespace webrtc
- #endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_
非Windows平臺下臨界區操作CriticalSectionPosix類 API 實現文件(critical_section_posix.cpp)
- #include "critical_section_posix.h"
- namespace webrtc {
- CriticalSectionPosix::CriticalSectionPosix()
- {
- pthread_mutexattr_t attr;
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&_mutex, &attr);
- }
- CriticalSectionPosix::~CriticalSectionPosix()
- {
- pthread_mutex_destroy(&_mutex);
- }
- void
- CriticalSectionPosix::Enter()
- {
- pthread_mutex_lock(&_mutex);
- }
- void
- CriticalSectionPosix::Leave()
- {
- pthread_mutex_unlock(&_mutex);
- }
- } // namespace webrtc<strong>
- </strong>
3、使用CriticalSectionWrapper和CriticalSectionScoped示例
設備池數據是臨界資源,爲保證臨界資源不被破壞,必須使用臨界區實現互斥訪問:
頭文件:...src\video_engine\main\test\WindowsTest\CaptureDevicePool.h
- #pragma once
- #include "common_types.h"
- #include "vie_base.h"
- #include "vie_capture.h"
- #include "vie_file.h"
- #include "map_wrapper.h"
- namespace webrtc {
- class CriticalSectionWrapper;
- }
- using namespace webrtc;
- class CaptureDevicePool
- {
- public:
- CaptureDevicePool(VideoEngine* videoEngine);
- ~CaptureDevicePool(void);
- WebRtc_Word32 GetCaptureDevice(int& captureId, const char uniqeDeviceName[256]);
- WebRtc_Word32 ReturnCaptureDevice(int captureId);
- private:
- struct DeviceItem
- {
- int captureId;
- WebRtc_Word32 refCount;
- char uniqeDeviceName[256];
- DeviceItem()
- {
- captureId=-1;
- refCount=0;
- }
- };
- CriticalSectionWrapper& _critSect;
- ViECapture* _vieCapture;
- ViEFile* _vieFile;
- MapWrapper _deviceMap;
- };
實現:...src\video_engine\main\test\WindowsTest\CaptureDevicePool.cpp
- #include "CaptureDevicePool.h"
- #include "map_wrapper.h"
- #include <string.h>
- #include <assert.h>
- #include "critical_section_wrapper.h"
- #include "vie_file.h"
- CaptureDevicePool::CaptureDevicePool(VideoEngine* videoEngine):
- _critSect(*CriticalSectionWrapper::CreateCriticalSection()),
- _vieCapture(ViECapture::GetInterface(videoEngine)),
- _vieFile(ViEFile::GetInterface(videoEngine))
- {
- }
- CaptureDevicePool::~CaptureDevicePool(void)
- {
- assert(_deviceMap.Size()==0);
- _vieCapture->Release();
- _vieFile->Release();
- delete &_critSect;
- }
- WebRtc_Word32 CaptureDevicePool::GetCaptureDevice(int& captureId, const char* uniqeDeviceName)
- {
- CriticalSectionScoped cs(_critSect); //創建CriticalSectionScoped cs即立刻進入臨界區,它的析構函數保證釋放臨界資源,保護對設備信息MapWrapper _deviceMap的訪問
- DeviceItem* device=NULL;
- for(MapItem* item=_deviceMap.First();
- item!=NULL;
- item=_deviceMap.Next(item))
- {
- //Found the device?先從臨界資源_deviceMap中查找Device,如果沒有的話就定位一個新的DeviceIterm
- if(strcmp(uniqeDeviceName,(static_cast<DeviceItem*>( item->GetItem()))->uniqeDeviceName)==0)
- {
- device=static_cast<DeviceItem*>( item->GetItem());
- device->refCount++;
- captureId=device->captureId;
- return 0;
- }
- }
- //沒找到Device定位一個新的Device
- device = new DeviceItem;
- strncpy(device->uniqeDeviceName,uniqeDeviceName,255);
- // Device does not exist. Create it.並將獲取到的設備放到DeviceItem device中去
- WebRtc_Word32 result=_vieCapture->AllocateCaptureDevice(device->uniqeDeviceName,strlen(device->uniqeDeviceName),device->captureId);
- if(result==0)
- {
- //配置設備的屬性
- //CaptureCapability cap;
- /*cap.height=1080;
- cap.width=1920;
- cap.maxFPS=25;
- cap.interlaced=true;*/
- // result=_vieCapture->StartCapture(device->captureId,cap);
- //設置捕捉設備初始圖片
- result=_vieFile->SetCaptureDeviceImage(device->captureId,"captureDeviceImage.jpg");
- }
- captureId=device->captureId; //返回新設備的ID給函數
- _deviceMap.Insert(captureId,device);//插入到MapWrapper _deviceMap中去
- device->refCount++; //引用加1
- return result;
- }
- WebRtc_Word32 CaptureDevicePool::ReturnCaptureDevice(int captureId)
- {
- CriticalSectionScoped cs(_critSect);
- MapItem* mapItem=_deviceMap.Find(captureId);
- if(!mapItem)
- return -1;
- DeviceItem* item=static_cast<DeviceItem*> (mapItem->GetItem());
- if(!item)
- return 0;
- item->refCount--;
- WebRtc_Word32 result=0;
- if(item->refCount==0)
- {
- result=_vieCapture->ReleaseCaptureDevice(captureId);
- _deviceMap.Erase(mapItem);
- delete item;
- }
- return result;
- }