【UE4源代码分析】-003 临界区

1 、临界区
   临界区 指的是一个访问共用资源(例如:共用设备或是共用存储器)的程序片段,而这些共用资源又无法同时被多个线程访问的特性。当有线程进入临界区段时,其他线程或是进程必须等待(例如: bounded waiting 等待法),有一些同步的机制必须在临界区段的进入点与离开点实现,以确保这些共用资源是被互斥获得使用。
   简单来说,临界区是一种锁,每次只允许一把钥匙对锁进行加锁操作。程序在使用临界资源之前需要使用自己的钥匙对锁进行加锁操作。加锁操作时,先检查锁是否处于锁定操作,如果处于锁定状态,那么需要等待锁被原加锁者解锁或超时。加锁成功后,程序可以使用临界资源。在使用完成之后需要使用钥匙对资源进行解锁。从而保证,同一时刻只有一个用户能够对临界资源进行访问。
   临界区 实现的是一种 互斥 的保护。
2 Windows 临界区
 &esmp;windows 提供了一种 CRITICAL_SECTION 结构,并提供相关操作函数来实现相关功能,主要包括:
// 初始化临界区
void WINAPI InitializeCriticalSection (LPCRITICAL_SECTION lpCriticalSection);
// 带自旋次数的初始化临界区
BOOL WINAPI InitializeCriticalSectionAndSpinCount (LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount);
// 设置临界区的自旋次数
DWORD WINAPI SetCriticalSectionSpinCount (LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount);
// 尝试进入临界区
BOOL WINAPI TryEnterCriticalSection (LPCRITICAL_SECTION lpCriticalSection);
// 进入临界区
void WINAPI EnterCriticalSection (LPCRITICAL_SECTION lpCriticalSection);
// 离开临界区
void WINAPI LeaveCriticalSection (LPCRITICAL_SECTION lpCriticalSection);
// 删除临界区,释放临界区
void WINAPI DeleteCriticalSection (LPCRITICAL_SECTION lpCriticalSection);
   CRITICAL_SECTION 并不是 windows 系统的核心对象,不具备名称。因此,临界区只能用于单个进程的多个线程之间的同步,对于进程之间的通信和同步无能为力。
3 UE4 中的临界区
   UE4 中, Engine\Source\Runtime\Core\Public\Windows\WindowsCriticalSection.h 文件提供了 UE4 中临界区的定义,主要包括 FWindowsCriticalSection FWindowsSystemWideCriticalSection 两种。
3.1 FWindowsCriticalSection
   FWindowsCriticalSection UE4 windows 操作系统中 CRITICAL_SECTION 结构的封装,提供无命名的临界区资源锁以及相关操作功能。
/**
 * This is the Windows version of a critical section. It uses an aggregate
 * CRITICAL_SECTION to implement its locking.
 */
class FWindowsCriticalSection
{
       // 私有成员, windows 普通的 CRITICAL_SECTION 变量
       Windows :: CRITICAL_SECTION CriticalSection;
 
public:
 
       // 构造函数,自旋次数初始值设置为 4000.
       FORCEINLINE FWindowsCriticalSection ()
       {
              CA_SUPPRESS ( 28125 );
              // 初始化临界区资源
              Windows :: InitializeCriticalSection ( & CriticalSection);
              Windows :: SetCriticalSectionSpinCount ( & CriticalSection, 4000 );
       }
 
       // 析构函数,释放临界区
       FORCEINLINE ~ FWindowsCriticalSection ()
       {
              Windows :: DeleteCriticalSection ( & CriticalSection);
       }
 
       // 加锁操作,采用先尝试,后进入的流程
       FORCEINLINE void Lock ()
       {
              // Spin first before entering critical section, causing ring-0 transition and context switch.
              if (Windows :: TryEnterCriticalSection ( & CriticalSection) == 0 )
              {
                    Windows :: EnterCriticalSection ( & CriticalSection);
              }
       }
 
       // 尝试加锁,当前临界区能够被当前线程加锁,则返回 true ,否则返回 false
       FORCEINLINE bool TryLock ()
       {
              if (Windows :: TryEnterCriticalSection ( & CriticalSection))
              {
                    return true ;
              }
              return false ;
       }
 
       // 解锁
       FORCEINLINE void Unlock ()
       {
              Windows :: LeaveCriticalSection ( & CriticalSection);
       }
 
private:
    // 确保临界区无法被复制和赋值
       FWindowsCriticalSection ( const FWindowsCriticalSection & );
       FWindowsCriticalSection & operator= ( const FWindowsCriticalSection & );
};
   通过将 FWindowsCriticalSection::FWindowsCriticalSection(const FWindowsCriticalSection&) FWindowsCriticalSection& FWindowsCriticalSection::operator=(const FWindowsCriticalSection&) 声明为私有函数,从而确保临界区资源锁无法被复制和赋值。
3.2 FWindowsSystemWideCriticalSection
   除了无法用于进程间同步的普通临界区之外, UE4 还通过 Mutex 模仿了一个可用于进程间同步的临界区 FWindowsSystemWideCriticalSection
  Mutex 是互斥器,在 windows 系统中是系统的核心对象,可以命名,并通过名称获取已经存在的对象实例。基于以上特性, UE4 通过 Mutex 的封装,实现了能够用于进程间线程同步的 FWindowsSystemWideCriticalSection ,其类定义如下:
/** System-Wide Critical Section for windows using mutex */
class CORE_API FWindowsSystemWideCriticalSection
{
public:
       // 构造函数,创建并尝试获取命名 Mutex
       explicit FWindowsSystemWideCriticalSection ( const class FString & InName, FTimespan InTimeout = FTimespan :: Zero ());
 
       // 析构函数,如果当前持有锁的话释放锁
       ~ FWindowsSystemWideCriticalSection ();
 
       // 检查锁当前是否能够获取,如果能够获取或者前一个拥有着在未释放锁的情况下结束了,返回 true ,否则返回 false
       bool IsValid () const ;
 
       // 释放锁
       void Release ();
 
private:
    // 防止锁被拷贝和赋值
       FWindowsSystemWideCriticalSection ( const FWindowsSystemWideCriticalSection & );
       FWindowsSystemWideCriticalSection & operator= ( const FWindowsSystemWideCriticalSection & );
 
private:
       Windows :: HANDLE Mutex;
};
 

猜你喜欢

转载自blog.csdn.net/freehawkzk/article/details/80579906