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)
-
- #ifndef CRITICAL_SECTION_WRAPPER_H
- #define CRITICAL_SECTION_WRAPPER_H
-
- namespace webrtc {
- class CriticalSectionWrapper
- {
- public:
-
- static CriticalSectionWrapper* CreateCriticalSection();
-
- virtual ~CriticalSectionWrapper() {}
-
-
-
- virtual void Enter() = 0;
-
-
- virtual void Leave() = 0;
- };
-
-
-
- class CriticalSectionScoped
- {
- public:
- CriticalSectionScoped(CriticalSectionWrapper& critsec)
- :
- _ptrCritSec(&critsec)
- {
- _ptrCritSec->Enter();
- }
-
- ~CriticalSectionScoped()
- {
- if (_ptrCritSec)
- {
- Leave();
- }
- }
-
- private:
- void Leave()
- {
- _ptrCritSec->Leave();
- _ptrCritSec = 0;
- }
-
- CriticalSectionWrapper* _ptrCritSec;
- };
- }
- #endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_
CriticalSectionWrapper类实现:(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();
- #else
- return new CriticalSectionPosix();
- #endif
- }
- }
Windows平台下临界区操作CriticalSectionWindows API 定义头文件(critical_section_windows.h)
-
- #ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_
- #define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_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;
-
-
- };
- }
-
- #endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_
Windows平台下临界区操作CriticalSectionWindows类 API 实现文件(critical_section_windows.cpp)
-
- #include "critical_section_windows.h"
-
- namespace webrtc {
- CriticalSectionWindows::CriticalSectionWindows()
- {
- InitializeCriticalSection(&crit);
- }
-
- CriticalSectionWindows::~CriticalSectionWindows()
- {
- DeleteCriticalSection(&crit);
-
- }
-
- void
- CriticalSectionWindows::Enter()
- {
- EnterCriticalSection(&crit);
- }
-
- void
- CriticalSectionWindows::Leave()
- {
- LeaveCriticalSection(&crit);
- }
- }
非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_
-
-
-
- #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;
-
- };
- }
-
- #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);
- }
- }
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);
-
- DeviceItem* device=NULL;
-
- for(MapItem* item=_deviceMap.First();
- item!=NULL;
- item=_deviceMap.Next(item))
- {
-
- if(strcmp(uniqeDeviceName,(static_cast<DeviceItem*>( item->GetItem()))->uniqeDeviceName)==0)
- {
- device=static_cast<DeviceItem*>( item->GetItem());
- device->refCount++;
- captureId=device->captureId;
- return 0;
- }
- }
-
- device = new DeviceItem;
- strncpy(device->uniqeDeviceName,uniqeDeviceName,255);
-
-
-
- WebRtc_Word32 result=_vieCapture->AllocateCaptureDevice(device->uniqeDeviceName
- ,strlen(device->uniqeDeviceName),device->captureId);
- if(result==0)
- {
-
-
-
-
-
-
-
-
- result=_vieFile->SetCaptureDeviceImage(device->captureId,"captureDeviceImage.jpg");
- }
- captureId=device->captureId;
- _deviceMap.Insert(captureId,device);
- device->refCount++;
-
- 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;
- }
(temotemo) |