mutex, spinlock, cas

2021-08-15  本文已影响0人  congchp

1.多线程数据共享,资源保护方法:
1)mutex
如果获取不到锁,让出CPU,将线程加入等待队列。

任务耗时比上下文切换要长

2)spinlock
如果获取不到锁,则继续死循环检查锁的状态,如果是lock状态,则继续死循环,否则上锁,结束死循环。

(1)任务不能存在阻塞 (2)任务耗时短,几条指令

3)无锁CAS(Compare and Swap)
比较并交换,是一种原子操作

bool CAS( int * pAddr, int nExpected, int nNew )
atomically {
    if ( *pAddr == nExpected ) {
        *pAddr = nNew ;
        return true ;
    } else
    return false ;
}

2.操作的原子性

#include <stdio.h>

int i = 0;
// gcc -S 1_test_i++.c
int main(int argc, char **argv)
{
    ++i;
    return 0;
}

++i 不是原子操作
汇编代码

    movl    i(%rip), %eax //把i从内存加载到寄存器
    addl    $1, %eax //把寄存器的值加1
    movl    %eax, i(%rip) //把寄存器的值写回内存
static int lxx_atomic_add(int *ptr, int increment)
{
    int old_value = *ptr;
    __asm__ volatile("lock; xadd %0, %1 \n\t"
                     : "=r"(old_value), "=m"(*ptr)
                     : "0"(increment), "m"(*ptr)
                     : "cc", "memory");
    return *ptr;
}

3.原子操作
gcc、g++编译器提供了一组原子操作api

bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)

C++11也提供了一组api,定义在<atomic>中

X86架构原子操作实现

static int lxx_atomic_add(int *ptr, int increment)
{
    int old_value = *ptr;
    __asm__ volatile("lock; xadd %0, %1 \n\t"
                     : "=r"(old_value), "=m"(*ptr)
                     : "0"(increment), "m"(*ptr)
                     : "cc", "memory");
    return *ptr;
}

4.无锁队列的实现
无锁队列适用于队列push、pop非常频繁的场景,效率要比mutex高很多

上一篇下一篇

猜你喜欢

热点阅读