一般的,我們在C++中有互斥鎖mutex , 條件鎖,自旋鎖SpinLock , 讀寫鎖RWLock .當然還有一些基於mutex的鎖,
C++11中提供的有:
- std::mutex,最基本的 Mutex 類。
- std::recursive_mutex,遞歸 Mutex 類。
- std::time_mutex,定時 Mutex 類。
- std::recursive_timed_mutex,定時遞歸 Mutex 類。
Lock有2類
- std::lock_guard,與 Mutex RAII 相關,方便線程對互斥量上鎖。
- std::unique_lock,與 Mutex RAII 相關,方便線程對互斥量上鎖,但提供了更好的上鎖和解鎖控制。
在Unigine中,其內部提供的Thread類相關方法,也大同小異。
- 原子操作AtomicAdd,實際上調用了window平臺的_InterlockedExchangeAdd, linux上的__sync_fetch_and_add 而已。
Unigine提供的方法有AtomicAdd,AtomicGet等。除了Thread類本身用外,只有內置Memory對象用到了
- 原子級別操作的AtomicCAS(標準CAS比較/交換算法)使用了windows的_InterlockedCompareExchange64,linux上的__sync_val_compare_and_swap
- 支持SpinLock ,基於上述AtomicAdd等原子操作,這在Unigine用的類對象比較廣泛,tileset, material , render,property等。
- 支持RWLock,基於上述AtomicAdd等原子操作,
這方面,Unigine的TerrainGlobal和FileSystem,用的比較多。
總體個人感覺,關於多線程或者線程鎖相關的內容,與其用Unigine內置的,還不如自己寫,畢竟它是個引擎,不是個大雜燴。
以下借用刷草的列子,介紹下如何使用Unigine中的Thread對象WorldSpawnGrassThread,
classWorldSpawnGrassThread : publicThread
{
public:
WorldSpawnGrassThread() {}
virtual ~WorldSpawnGrassThread() {}
protected:
virtualvoid process();
};
voidWorldSpawnGrassThread::process()
{
while (isRunning())
engine.world->processSpawnGrass();
}
重要方法就是void process(), 父線程中的virtual函數實現即可。
早期Uniginev2.5的時候刷草代碼沒有做線程的lock,在Update時刪除草對象等行爲時會奔潰。較新的代碼中每個線程對象分配了一個類似下面的lock對象。
volatileintworld_spawn_mesh_clutter_lock;
在進行多線程操作的時候用
SpinLock(lock, 0, 1); //開啓開啓自旋鎖
XXX-》執行很多內容
SpinLock(lock, 1, 0); //關閉自旋鎖