atomic自旋锁的实现原理

相信大家都听过牛逼哄哄的自旋锁,最近看php-fpm源码发现里面有实现代码,就研究了一下

直接粘代码

//自旋锁
static inline int fpm_spinlock(atomic_t *lock, int try_once) /* {{{ */
{
    //尝试获取一次锁
    if (try_once) {
        return atomic_cmp_set(lock, 0, 1) ? 1 : 0;
    }
    //尝试获取锁,直到获取到
    for (;;) {
        //设置自旋锁,设置成功,则表示获取到锁
        if (atomic_cmp_set(lock, 0, 1)) {
            break;
        }
       
        sched_yield();//让出cpu等待下次调度
    }

    return 1;
}

//代码中对不同的处理器有不同的处理方式,但是原理是一样的,下面是__amd64__,__amd64,__x86_64__处理器下的实现方式
static inline atomic_uint_t atomic_cmp_set(atomic_t *lock, atomic_uint_t old, atomic_uint_t set) /* {{{ */
{
    unsigned char res;
    /*
     * 这是段内嵌汇编,内嵌汇编是GCC对汇编的封装,具体可以自行google,下面只介绍这段程序的实现原理
     * lock指令会使 CPU 宣告一个 LOCK# 信号,这样就能确保在多处理器系统或多线程竞争的环境下互斥地使用这个内存地址。当指令执行完毕,这个锁定动作也就会消失。
     * cmpxchgq:其中"=a" (res)和"a" (old)表示操作数使用的寄存器是eax,"m" (*lock)对应%1,"r" (set)对应%3;    
     * 指令的含义是用lock与old的值比较,如果相等,ZF标志被设置,把set的值写到 lock,否则,清ZF标志,把lock的值写到old。
     */

    __asm__ volatile ( "lock;" "cmpxchgq %3, %1;" "sete %0;" :
        "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "memory");

    return res;
}

/* 原理精简:使用atomic_cmp_set获取到锁的时候lock的值变为1,然后其他线程的lock就变成1了,再调用atomic_cmp_set就会一直失败,直到lock被释放,即重新变成0 */

转载请注明:小Y » atomic自旋锁的实现原理

赞 (2) 评论 (0) 分享 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址