CAS无锁队列与线程同步

线程同步

同步:同步控制着线程之间的执行顺序,不让他们抢占式执行。在保证数据安全的前提下,让线程能够按照某种特定的顺序访问临界资源,从而有效避免饥饿问题,叫做同步。

原子访问:同一时刻,只允许一个线程访问临界资源;

原子操作:指多步操作组成的一个操作;原子操作中线程不会被切换,线程切换要么在原子操作之前,要么在原子操作完成之后。

在单核系统里,单个的机器指令可以看成是原子操作(如果有编译器优化、乱序执行等情况除外);在多核系统中,单个的机器指令就不是原子操作,因为多核系统里是多指令流并行运行的,一个核在执行一个指令时,其他核同时执行的指令有可能操作同一块内存区域,从而出现数据竞争现象。多核系统中的原子操作通常使用内存栅障(memory barrier)来实现,即一个CPU核在执行原子操作时,其他CPU核必须停止对内存操作或者不对指定的内存进行操作,这样才能避免数据竞争问题。

CAS无锁队列:

避免队列放入和读取过于频繁。volatile 修饰变量+type __sync_val_compare_and_swap (type *ptr, type oldval type newval)

CAS原理:compare and swap;比较内存有没有被修改,期望值和读出来的值是否一致

应用:无锁队列,ZMQ中的设计用到了cas无锁队列; disruptor库。会涉及到cache的操作的问题:每个CPU都有独立的cache, 当cache修改了,cache1和cache2会失效的问题;

缺点:出了问题很难debug;考验设计能力;

mutex互斥锁:如果获取不到锁,线程就会进入休眠,让出CPU资源,线程加入到所等待队列中;

缺点:切换上下文引起的效率的问题;要避免频繁的切换上下文成为应用场景的选择;

临界区执行代码比较长时mutexspinlock相比较会占优势一点;比如:for(i =0 ;i <10000;i++){sum++;}

spinlock自旋锁:

特点:忙等待,继续去检测锁的状态;

应用场景中:1.临界区内不能存在阻塞;2,临界区代码段执行时间不能过长,比如:i++;++i......

++i;i++;

  1. i从内存加载到寄存器;
  2. 执行操作;
  3. 写回内存;

gcc -S Filenale.c

Vim Filenam.s

其反汇编代码:

movl  i(%rip),  %eax

addl  $1,  %eax

movl  %eax,  i(%rip)

原子操作指令API:add,sub,or,and,xor,nand

X86内存汇编指令加操作:lxx_atomic_add(&s_i, 1);

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;

}

猜你喜欢

转载自www.cnblogs.com/will287248100/p/13205886.html