gcc-9.1.0\libsanitizer\sanitizer_common\sanitizer_mutex.h
这个文件一共定义了四个基本的类,分别是:
1. class StaticSpinMutex
StaticSpinMutex类拥有一个无符号型8位原子性字段:state_,1表示上锁,0表示空闲。显然这个变量是用于记录锁的状态的
成员函数主要为:Init(), Lock(), TryLock(), Unlock(), CheckLocked()
五个,均使用Sanitizer Atomic中提到的原子操作实现。唯一复杂一点的函数是Lock(),代码如下:
void Lock() {
if (TryLock())
return;
LockSlow();
}
bool TryLock() {
return atomic_exchange(&state_, 1, memory_order_acquire) == 0;
}
void NOINLINE LockSlow() {
for (int i = 0;; i++) {
if (i < 10)
proc_yield(10);
else
internal_sched_yield();
if (atomic_load(&state_, memory_order_relaxed) == 0
&& atomic_exchange(&state_, 1, memory_order_acquire) == 0)
return;
}
}
Lock() 函数首先调用了 TryLock() 获取锁,当锁正忙时,就启用 LockSlow() ,LockSlow() 函数通过循环挂起不断尝试获取锁,一共分两步:
-
调用了两个相似的函数 proc_yield 和 internal_sched_yield,我个人理解的是 proc_yield 是一种假的挂起,调用这个函数不会将当前进程交换出执行队列,而 internal_sched_yield 是真的将该进程换出执行队列让出CPU,等待下次被调度放入CPU执行。就像一个公共厕所,我第一次到的时候首先试着等了10分钟,结果一直有人用,于是我先回到自己的座位,休息会儿又来看一眼还有没有人用,发现还有人用,于是回去接着等会再来,不断循环直到开始使用公厕。
-
通过atomic_load(),检查当前锁是否空闲,然后通过atomic_exchange获得锁的使用权,只有当都成功以后,才表示成功获得锁。
2. class SpinMutex : public StaticSpinMutex
包括三个函数:一个默认构造函数,一个拷贝构造函数和一个运算符“=”重载函数
3. class BlockingMutex
首先这个类的构造函数声明如下:
explicit constexpr BlockingMutex(LinkerInitialized)