日常多线程开发过程中,线程同步是最基本的需求,各操作系统也给我们提供了相应的同步内核对象,例如Windows中的原子(Atomic),临界区(Critical Section),互斥量(Mutex),信号量(Semaphore),还有事件(Event),做过Windows或者Linux C++开发的朋友,对这些东西肯定非常熟悉了,这些都属于内核对象,是系统层面提供的,QT,UE4等其他工具只是实现了对这些内核对象的封装而已,所以这些东西的原理也都大差不差,一通百通,虚幻引擎也是在上层抽象出了不同平台的接口,在windows平台下,虚幻C++临界区的代码片段如下
class FWindowsCriticalSection
{
Windows::CRITICAL_SECTION CriticalSection;
public:
FORCEINLINE FWindowsCriticalSection()
{
CA_SUPPRESS(28125);
Windows::InitializeCriticalSection(&CriticalSection);
Windows::SetCriticalSectionSpinCount(&CriticalSection,4000);
}
FORCEINLINE ~FWindowsCriticalSection()
{
Windows::DeleteCriticalSection(&CriticalSection);
}
FORCEINLINE void Lock()
{
Windows::EnterCriticalSection(&CriticalSection);
}
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&);
};
跟踪一下,Windows::InitializeCriticalSection(&CriticalSection);,在Windows平台下它确实调用的是Windows系统的InitializeCriticalSection API函数
UE4的线程同步对象有很多,今天我们先来看一下线程锁,FScopeLock,它实现了一个区域级别的锁,它的实现需要注意两点
- 构造FScopeLock时需要一个临界区对象
FCriticalSection cs;
- 用大括号将需要同步的代码块包住,FScoppeLock的对象放在大括号第一行(待验证,UE4引擎中有些代码并没有按照这个规则 )
FScopeLock lock(cs);
伪代码如下
#include "Misc/ScopeLock.h"
void ThreadFunction()
{
//不需要同步代码块
{
//需要同步代码块,lock必须在第一行
FScopeLock lock(&cs);
}
//不需要同步代码块
}
那此时大括号的内容就被锁住,同一时间,只允一个线程访问临界资源