一般的,我们在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); //关闭自旋锁