TAS 指令与PostgreSQL spin lock

本文详细介绍了如何使用TAS指令在PostgreSQL中实现SpinLock,包括使用volatile关键字确保内存一致性,以及如何在多线程环境中正确地进行锁的申请与释放。此外,还探讨了SpinLock的实现细节,包括使用semaphore和TAS两种方法,并解释了自适应算法如何决定spin次数和睡眠时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    TAS: 指Test-And-Set,它是一个原子操作,修改内存的值,并返回原来的值。当一个进程P1对一个内存位置做TAS操作,不允许其它进程P2对此内存位置,再做TAS操作。

P2必须等P1操作完成后,再做TAS操作。以下是一个简单的锁,通过TAS来实现:



volatile int lock = 0;
void Critical() {
    while (TestAndSet(&lock) == 1);
    critical section // only one process can be in this section at a time 
    lock = 0 // release lock when finished with the critical section 
假设lock原来的值为“0”,当P1去做申请lock时,能获取得到锁。而此时P2再去申请锁时,必须spin,因为此时lock的值已经被P1修改为“1”了。

用TAS来实现spin lock,此处要注意volatile的使用。volatile表示这个变量是易失的,所以会编译器会每次都去内存中取原始值,而不是直接拿寄存器中的值。
这避免了在多线程编程中,由于多个线程更新同一个变更,内存中和寄存器中值的不同步而导致变量的值错乱的问题。另外,也会影响编译器的优化行为。


在PostgreSQL中,spin lock的实现包含在spin.c和s_lock.c两个文件中。在不支持TAS的情况下,PG会使用PGSemaphores来实现 spin lock。
 
1.使用semaphore实现 
其中spin.c主要封装了spin lock用PGSemaphores来实现的接口,跟硬件保持独立。PGSemaphore是使用OS底层的semaphore来实现的,PG对其做了封装,提供了PG系统内部统一的semaphore操作接口。
PG的用PGSemaphore结构体表示PG 自身的semaphore信号,并将相关操作封装在sembuf中,传递给底层OS。
PG semaphore lock操作:




PG semaphore结构体:

操作封装:

semop操作:



底层OS实现调用,OS声明在/usr/sys/include/sem.h中 




从上面可以看出,PG的semaphore实现非常清晰,而且与OS底层的调用关系也很明了。
 
2.使用TAS指令实现 
而s_lock.c 则用TAS方式了spin lock,与硬件相关。在PG源码中,使用s_lock函数来申请spin lock:
int s_lock(volatile slock_t *lock, const char *file, int line)
tas操作如下:


PG使用了自适应算法,来决定spin的次数和每次spin后,sleep的时间。

spins_per_delay:spin多少次后,开始sleep。默认为100,最大值为1000,最小值为10。

cur_delay:当前sleep的时间,最大值为1000,最小值为1。单位为毫秒。

spins_per_delay的值,基本上不变;但是cur_delay的值为当前值1倍和2倍之间变动。因此,spin delay次数越多,sleep时间会越长。

 

 

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30088583/viewspace-1512121/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30088583/viewspace-1512121/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值