WebRTC音视频引擎研究(3)--临界区设计、临界资源访问--CriticalSectionWrapper

来源:互联网 发布:qq卡屏源码 编辑:程序博客网 时间:2024/05/16 19:29

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)

[cpp] view plaincopy
  1. //=========critical_section_wrapper.h  
  2. #ifndef CRITICAL_SECTION_WRAPPER_H  
  3. #define CRITICAL_SECTION_WRAPPER_H  
  4.   
  5. namespace webrtc {  
  6.     class CriticalSectionWrapper  
  7.     {  
  8.     public:  
  9.         // Factory method, constructor disabled  
  10.         static CriticalSectionWrapper* CreateCriticalSection();//工厂方法,创建临界区,返回指针  
  11.   
  12.         virtual ~CriticalSectionWrapper() {}  
  13.   
  14.         // Tries to grab lock, beginning of a critical section. Will wait for the  
  15.         // lock to become available if the grab failed.  
  16.         virtual void Enter() = 0;  
  17.   
  18.         // Returns a grabbed lock, end of critical section.  
  19.         virtual void Leave() = 0;  
  20.     };  
  21.   
  22.     // RAII extension of the critical section. Prevents Enter/Leave missmatches and  
  23.     // provides more compact critical section syntax.  
  24.     class CriticalSectionScoped  
  25.     {  
  26.     public:  
  27.         CriticalSectionScoped(CriticalSectionWrapper& critsec) //构造函数,进入临界区  
  28.             :  
  29.         _ptrCritSec(&critsec)  
  30.         {  
  31.             _ptrCritSec->Enter();  
  32.         }  
  33.   
  34.         ~CriticalSectionScoped() //析构函数,保证离开临界区  
  35.         {  
  36.             if (_ptrCritSec)  
  37.             {  
  38.                 Leave();  
  39.             }  
  40.         }  
  41.   
  42.     private:  
  43.         void Leave()  
  44.         {  
  45.             _ptrCritSec->Leave();  
  46.             _ptrCritSec = 0;  
  47.         }  
  48.   
  49.         CriticalSectionWrapper* _ptrCritSec;  
  50.     };  
  51. // namespace  
  52. #endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_  

CriticalSectionWrapper类实现:(critical_section.cpp)

[cpp] view plaincopy
  1. //=========== critical_section.cpp  
  2. #if defined(_WIN32)  
  3. #include <windows.h>   
  4. #include "critical_section_windows.h" //使用Windows平台API  
  5. #else  
  6. #include "critical_section_posix.h" //使用posix  
  7. #endif  
  8.   
  9. namespace webrtc {  
  10.     CriticalSectionWrapper* CriticalSectionWrapper::CreateCriticalSection()  
  11.     {  
  12. #ifdef _WIN32  
  13.         return new CriticalSectionWindows();//Windows平台,返回CriticalSectionWindows对象  
  14. #else  
  15.         return new CriticalSectionPosix(); //非Windows平台,返回CriticalSectionPosix对象  
  16. #endif  
  17.     }  
  18. // namespace webrt<strong>  
  19. </strong>  



Windows平台下临界区操作CriticalSectionWindows API 定义头文件(critical_section_windows.h)

[cpp] view plaincopy
  1. //============== critical_section_windows.h  
  2. #ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_  
  3. #define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_  
  4.   
  5. //#include "typedefs.h"  
  6. #include "critical_section_wrapper.h"  
  7. #include <windows.h>  //使用Windows平台API  
  8.   
  9. namespace webrtc {  
  10.     class CriticalSectionWindows : public CriticalSectionWrapper  
  11.     {  
  12.     public:  
  13.         CriticalSectionWindows();  
  14.   
  15.         virtual ~CriticalSectionWindows();  
  16.   
  17.         virtual void Enter();  
  18.         virtual void Leave();  
  19.   
  20.     private:  
  21.         CRITICAL_SECTION crit;  
  22.   
  23.         //friend class ConditionVariableWindows;  
  24.     };  
  25. // namespace webrtc  
  26.   
  27. #endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_  

Windows平台下临界区操作CriticalSectionWindows类 API 实现文件(critical_section_windows.cpp)

[cpp] view plaincopy
  1. //============= critical_section_windows.cpp  
  2. #include "critical_section_windows.h"  
  3.   
  4. namespace webrtc {  
  5.     CriticalSectionWindows::CriticalSectionWindows()  
  6.     {  
  7.         InitializeCriticalSection(&crit);   //构造函数初始化临界区  
  8.     }  
  9.   
  10.     CriticalSectionWindows::~CriticalSectionWindows()  
  11.     {  
  12.         DeleteCriticalSection(&crit);//析构函数删除临界区,利用类来管理资源的思想,Effective C++思想  
  13.     }  
  14.   
  15.     void  
  16.         CriticalSectionWindows::Enter()  
  17.     {  
  18.         EnterCriticalSection(&crit);        //进入临界资源  
  19.     }  
  20.   
  21.     void  
  22.         CriticalSectionWindows::Leave()  
  23.     {  
  24.         LeaveCriticalSection(&crit);        //离开临界资源  
  25.     }  
  26. // namespace webrtc<strong>  
  27. </strong>  


非Windows平台下临界区操作CriticalSectionPosix API 定义头文件(critical_section_posix.h)

[cpp] view plaincopy
  1. #ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_  
  2. #define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_  
  3.   
  4. //非Windows平台使用Posix的临界资源  
  5.   
  6. #include "critical_section_wrapper.h"  
  7.   
  8. #include <pthread.h> //使用Posix  
  9.   
  10. namespace webrtc {  
  11. class CriticalSectionPosix : public CriticalSectionWrapper  
  12. {  
  13. public:  
  14.     CriticalSectionPosix();  
  15.   
  16.     virtual ~CriticalSectionPosix();  
  17.   
  18.     virtual void Enter();  
  19.     virtual void Leave();  
  20.   
  21. private:  
  22.     pthread_mutex_t _mutex;  
  23.     //friend class ConditionVariablePosix;  
  24. };  
  25. // namespace webrtc  
  26.   
  27. #endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_  

非Windows平台下临界区操作CriticalSectionPosix类 API 实现文件(critical_section_posix.cpp)


[cpp] view plaincopy
  1. #include "critical_section_posix.h"  
  2.   
  3. namespace webrtc {  
  4. CriticalSectionPosix::CriticalSectionPosix()  
  5. {  
  6.     pthread_mutexattr_t attr;  
  7.     pthread_mutexattr_init(&attr);  
  8.     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);  
  9.     pthread_mutex_init(&_mutex, &attr);  
  10. }  
  11.   
  12. CriticalSectionPosix::~CriticalSectionPosix()  
  13. {  
  14.     pthread_mutex_destroy(&_mutex);  
  15. }  
  16.   
  17. void  
  18. CriticalSectionPosix::Enter()  
  19. {  
  20.     pthread_mutex_lock(&_mutex);  
  21. }  
  22.   
  23. void  
  24. CriticalSectionPosix::Leave()  
  25. {  
  26.     pthread_mutex_unlock(&_mutex);  
  27. }  
  28. // namespace webrtc<strong>  
  29. </strong>  

3、使用CriticalSectionWrapper和CriticalSectionScoped示例

设备池数据是临界资源,为保证临界资源不被破坏,必须使用临界区实现互斥访问:

头文件:...src\video_engine\main\test\WindowsTest\CaptureDevicePool.h

[cpp] view plaincopy
  1. #pragma once  
  2.   
  3. #include "common_types.h"  
  4.   
  5. #include "vie_base.h"  
  6. #include "vie_capture.h"  
  7. #include "vie_file.h"  
  8. #include "map_wrapper.h"  
  9.   
  10. namespace webrtc {  
  11. class CriticalSectionWrapper;  
  12. }  
  13. using namespace webrtc;  
  14. class CaptureDevicePool  
  15. {  
  16. public:  
  17.     CaptureDevicePool(VideoEngine* videoEngine);  
  18.     ~CaptureDevicePool(void);  
  19.     WebRtc_Word32 GetCaptureDevice(int& captureId, const char uniqeDeviceName[256]);  
  20.     WebRtc_Word32 ReturnCaptureDevice(int captureId);  
  21.   
  22.     private:   
  23.         struct DeviceItem  
  24.         {  
  25.             int captureId;  
  26.             WebRtc_Word32 refCount;  
  27.             char uniqeDeviceName[256];  
  28.             DeviceItem()  
  29.             {  
  30.                 captureId=-1;  
  31.                 refCount=0;  
  32.             }  
  33.         };  
  34.         CriticalSectionWrapper& _critSect;  
  35.         ViECapture* _vieCapture;  
  36.         ViEFile*    _vieFile;  
  37.         MapWrapper _deviceMap;  
  38.   
  39. };  

实现:...src\video_engine\main\test\WindowsTest\CaptureDevicePool.cpp

[cpp] view plaincopy
  1. #include "CaptureDevicePool.h"  
  2. #include "map_wrapper.h"  
  3. #include <string.h>  
  4. #include <assert.h>  
  5. #include "critical_section_wrapper.h"  
  6. #include "vie_file.h"  
  7.   
  8. CaptureDevicePool::CaptureDevicePool(VideoEngine* videoEngine):  
  9. _critSect(*CriticalSectionWrapper::CreateCriticalSection()),  
  10. _vieCapture(ViECapture::GetInterface(videoEngine)),  
  11. _vieFile(ViEFile::GetInterface(videoEngine))  
  12. {  
  13. }  
  14.   
  15. CaptureDevicePool::~CaptureDevicePool(void)  
  16. {  
  17.     assert(_deviceMap.Size()==0);  
  18.     _vieCapture->Release();  
  19.     _vieFile->Release();  
  20.     delete &_critSect;  
  21. }  
  22.   
  23. WebRtc_Word32 CaptureDevicePool::GetCaptureDevice(int& captureId, const char* uniqeDeviceName)  
  24. {  
  25.     CriticalSectionScoped cs(_critSect); //创建CriticalSectionScoped cs即立刻进入临界区,它的析构函数保证释放临界资源,保护对设备信息MapWrapper _deviceMap的访问  
  26.     DeviceItem* device=NULL;  
  27.       
  28.     for(MapItem* item=_deviceMap.First();  
  29.         item!=NULL;  
  30.         item=_deviceMap.Next(item))  
  31.     {  
  32.         //Found the device?先从临界资源_deviceMap中查找Device,如果没有的话就定位一个新的DeviceIterm  
  33.         if(strcmp(uniqeDeviceName,(static_cast<DeviceItem*>( item->GetItem()))->uniqeDeviceName)==0)  
  34.         {  
  35.             device=static_cast<DeviceItem*>( item->GetItem());  
  36.             device->refCount++;  
  37.             captureId=device->captureId;  
  38.             return 0;  
  39.         }  
  40.     }  
  41.     //没找到Device定位一个新的Device  
  42.     device = new DeviceItem;  
  43.     strncpy(device->uniqeDeviceName,uniqeDeviceName,255);  
  44.   
  45.   
  46.     // Device does not exist. Create it.并将获取到的设备放到DeviceItem device中去  
  47.     WebRtc_Word32 result=_vieCapture->AllocateCaptureDevice(device->uniqeDeviceName,strlen(device->uniqeDeviceName),device->captureId);  
  48.     if(result==0)  
  49.     {  
  50.         //配置设备的属性  
  51.         //CaptureCapability cap;  
  52.         /*cap.height=1080; 
  53.         cap.width=1920; 
  54.         cap.maxFPS=25;     
  55.         cap.interlaced=true;*/  
  56.      //   result=_vieCapture->StartCapture(device->captureId,cap);  
  57.         //设置捕捉设备初始图片  
  58.         result=_vieFile->SetCaptureDeviceImage(device->captureId,"captureDeviceImage.jpg");  
  59.     }  
  60.     captureId=device->captureId;         //返回新设备的ID给函数  
  61.     _deviceMap.Insert(captureId,device);//插入到MapWrapper _deviceMap中去  
  62.     device->refCount++;                      //引用加1  
  63.       
  64.     return result;  
  65.   
  66.   
  67. }  
  68. WebRtc_Word32 CaptureDevicePool::ReturnCaptureDevice(int captureId)  
  69. {  
  70.     CriticalSectionScoped cs(_critSect);  
  71.   
  72.     MapItem* mapItem=_deviceMap.Find(captureId);  
  73.     if(!mapItem)  
  74.         return -1;  
  75.   
  76.     DeviceItem* item=static_cast<DeviceItem*> (mapItem->GetItem());  
  77.     if(!item)  
  78.         return 0;  
  79.     item->refCount--;  
  80.     WebRtc_Word32 result=0;  
  81.   
  82.     if(item->refCount==0)  
  83.     {  
  84.         result=_vieCapture->ReleaseCaptureDevice(captureId);  
  85.           
  86.         _deviceMap.Erase(mapItem);  
  87.         delete item;  
  88.   
  89.     }  
  90.     return result;  
0 0
原创粉丝点击