各种类型的锁与原子操作

1、什么情况下,需要锁

一行代码翻译若干条指令,加锁将多条指令不被拆分。

2、lock、trylock、spinlock

locktrylockspinlock
线程会休眠线程不会主动休眠线程不会休眠
线程A锁住后,线程B再去申请锁,会引起线程B的挂起,会引起线程状态的切换线程B状态有可能被切换线程B状态不会被切换,时间片到了也不会引起状态切换
适用于时间长(大于线程切换时间)粒度大适用于时间短(小于线程切换时间)粒度小

3、线程切换有两种情况:

1)、运行时,时间片用完,引起切换,被调度时间用完,进入ready状态。

2)、运行中,等待某种条件,如io没有就绪或被锁住,引起的切换,进入wait状态。

4、读写锁

rwlock,两种方式加锁(写加锁、读加锁)、适用于读多写少(读不冲突、写冲突,多线程同时读)的场景,使用方法读时加锁,写时也加锁。

5、原子操作,粒度更小,需要指令系统里有相关指令,才能够实现原子操作 。

不是所有代码都能变成原子操作,例如双向队列,头插法加节点,三行代码实现,如果要原子操作的话,则需要同时对多个地址赋值的指令,但是同时对多个地址进行mov操作的指令系统里是没有的,所以无法实现原子操作。

volatile关键字 内存中易变的变量,CPU每次取该变量的值都会去内存取一遍,而不是直接使用寄存器里的值。

//value++,原子操作
int inc(int *value, int add) {

    int old;

    __asm__ volatile ( //汇编语法开头写法,构建了原子操作,x86汇编语言
        "lock; xaddl %2, %1;" // "lock; xchg %2, %1, %3;" 汇编语句:%2+%1值存储到%1中,
                              //lock:锁住总线,避免多个CPU操作一个内存块
        : "=a" (old)//占位符
        : "m" (*value), "a" (add)//%1、%2。
        : "cc", "memory"//cpu、高速缓存、主内存。高速缓存和内存之间的一致性问题,MESI四状态、
                        //高速缓存写回到内存,设置内存屏障不受其他CPU指令干扰操作此内存块。
    );

    return old;
}

Compare And Swap -->CAS

//无锁 CAS 原子操作
int inc(int *value, int b, int c) {

    int old;

    __asm__ volatile ( 
        "lock; xchg %2, %1, %3;"
        : "=a" (old)
        : "m" (*value), "a" (b), "b"(c)
        : "cc", "memory"
    );

    return old;
}

if (a == b)
{
    a = c;
}


xchg(instance,NULL,newobject)

6、多进程如何加锁

共享内存,进程操作共享内存,可以将lock、trylock、spinlock、原子操作在共享内存中使用。

int main()
{
    int *pcount = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
//mmap只适用于父子进程。匿名方式只适合父子进程。若是使用文件fd,则和父子进程没有关系,可以用在任意进程之间。

    int i = 0;
    pid_t pid = 0;
    for (i=0; i< 10; i++)
    {
        pid = fork();
        if ( pid <= 0 )
        {
            usleep(1);
            break;
        }
    }
    
    if ( pid > 0 )
    {
        for (i = 0;i < 100;i ++) //父进程查看
        {
            printf("count --> %d\n",  (*pcount));
            sleep(1);
        }

    } else
    {
        //子进程进行累加
        int i = 0;
        while (i++ < 100000)  
        {
#if 0            
            (*pcount) ++;
#else
            inc(pcount, 1);
#endif
            usleep(1);
        }

    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值