LWLock实现的技术
上一节,我们介绍了LWLock的数据结构,其中LWLock锁的“state”上的锁标志可以有两种模式,如下:
typedef enum LWLockMode
{
LW_EXCLUSIVE, //排他模式
LW_SHARED, //共享模式
LW_WAIT_UNTIL_FREE /* A special mode used in PGPROC->lwlockMode,
* when waiting for lock to become free. Not
* to be used as LWLockAcquire argument */
} LWLockMode;
而LWLock结构体定义了state标志位(LWLock锁的数据结构参见上一节),此标志位是通过LWLockAcquire ()对LWLockAttemptLock()函数调用完成标志位设置的。
LWLockAttemptLock(LWLock *lock, LWLockMode mode)
{...
old_state = pg_atomic_read_u32(&lock->state); //读出锁的原始值
while (true)
{...
desired_state = old_state; //desired_state上先保持旧值
if (mode == LW_EXCLUSIVE)
{
lock_free = (old_state & LW_LOCK_MASK) == 0;
if (lock_free)
desired_state += LW_VAL_EXCLUSIVE; //desired_state上先保持旧值后,根据锁的模式加排它锁的标识
}
else
{
lock_free = (old_state & LW_VAL_EXCLUSIVE) == 0;
if (lock_free)
desired_state += LW_VAL_SHARED; //desired_state上先保持旧值后,根据锁的模式加共享锁的标识
}
//desired_state成为在锁标志位上将被设置的值。pg_atomic_compare_exchange_u32()完成设置标志位(不同硬件平台,设置方式不同)
if (pg_atomic_compare_exchange_u32(&lock->state, &old_state, desired_state))
{
...
}
}
...
}
而pg_atomic_compare_exchange_u32()函数调用的其它函数,因硬件平台而异,如在Windows下,调用栈如下,最终使用了InterlockedCompareExchange()函数完成锁标志位的置位工作,state标志位被设置为“LW_VAL_SHARED”或“LW_VAL_EXCLUSIVE”。
LWLockAcquire()
LWLockAttemptLock()
pg_atomic_compare_exchange_u32()
pg_atomic_compare_exchange_u32_impl()
InterlockedCompareExchange() //把目标操作数(第1参数所指向的内存中的数)与一个值(第3参数)比较,如果相等,则用另一个值(第2参数)与目标操作数(第1参数所指向的内存中的数)交换
另外,释放锁时也需要对锁标志位置位为“LW_FLAG_RELEASE_OK”,且无“LW_VAL_SHARED”也无“LW_VAL_EXCLUSIVE”,置位操作通过pg_atomic_sub_fetch_u32()函数完成,如下是在Windows下的调用栈示例。
LWLockRelease()
pg_atomic_sub_fetch_u32()
pg_atomic_sub_fetch_u32_impl()
pg_atomic_fetch_sub_u32_impl()
pg_atomic_fetch_add_u32_impl()
InterlockedExchangeAdd() //用于对一个32位数值执行加法的原子操作