lock free(无锁并发)是什么

1、非阻塞同步(Non-blocking Synchronization)

1. 无锁编程 / lock-free / 非阻塞同步

无锁编程,即不使用锁的状况下实现多线程之间的变量同步,也就是在没有线程被阻塞的状况下实现变量的同步,因此也叫非阻塞同步(Non-blocking Synchronization)。html

实现非阻塞同步的方案称为“无锁编程算法”( Non-blocking algorithm)。算法

lock-free是目前最多见的无锁编程的实现级别(一共三种级别):编程

  • wait-free
  • lock-free
  • obstruction-free

 

2. 为何要 Non-blocking sync ?

使用lock实现线程同步有不少缺点:安全

* 产生竞争时,线程被阻塞等待,没法作到线程实时响应。数据结构

* dead lock。多线程

* live lock。并发

* 优先级翻转。ide

* 使用不当,形成性能降低。oop

 

3. wait-free

是最理想的模式,整个操做保证每一个线程在有限步骤下完成。性能

保证系统级吞吐(system-wide throughput)以及无线程饥饿。

截止2011年,没有多少具体的实现。即便实现了,也须要依赖于具体CPU。

 

4. lock-free

容许个别线程饥饿,但保证系统级吞吐。

确保至少有一个线程可以继续执行。

wait-free的算法一定也是lock-free的。

 

5. obstruction-free

在任什么时候间点,一个线程被隔离为一个事务进行执行(其余线程suspended),而且在有限步骤内完成。

在执行过程当中,一旦发现数据被修改(采用时间戳、版本号),则回滚。

也叫作乐观锁,即乐观并发控制(OOC)。

事务的过程是:1读取,并写时间戳;2准备写入,版本校验;3校验经过则写入,校验不经过,则回滚。

 

2、CAS

CAS( compare and swap) 原子操做,用来实现多线程下的变量同步。

保证了若是须要更新的地址没有被其余进程(线程)改动过,那么它能够安全的写入。

而这也是咱们对于某个数据或者数据结构加锁要保护的内容,保证读写的一致性,不出现dirty data。

 

CAS原语有三个参数:

  • 内存地址,
  • 指望值,
  • 新值。

 

算法逻辑:

  • 若是内存地址的值==指望值,表示该值未修改,此时能够修改为新值。
  • 不然表示修改失败,返回false,由用户决定后续操做。
int compare_and_swap (int* reg, int oldval, int newval) {
  ATOMIC();
  int old_reg_val = *reg;
  if (old_reg_val == oldval)
     *reg = newval;
  END_ATOMIC();
  return old_reg_val;
}

可在循环中不断执行CAS,若是共享变量没有改变,那么swap,在当前环境中写入,不然继续do-while的Retry-Loop。

 

 

3、ABA问题

ABA问题最容易发生在lock free算法中的,地址被重用的状况。

无锁至关于“锁”的粒度变小了,主要是“锁”HEAD和TAIL这两个关键资源。而不是整个数据结构。

 

thread1意图对val=1进行操做变成2,cas(*val,1,2)。

thread1先读取val=1;thread1被抢占(preempted),让thread2运行。

thread2 修改val=3,又修改回1。

thread1继续执行,发现指望值与“原值”(其实被修改过了)相同,完成CAS操做。

 

使用CAS会形成ABA问题,特别是在使用指针操做一些并发数据结构时。

 

解决方案

ABAʹ:添加额外的标记用来指示是否被修改。

# Java demo
 
AtomicInteger atom = new AtomicInteger(1);

boolean r = atom.compareAndSet(1, 2);

 

# C# demo

int i=1;

Interlocked.Increment(ref i);
相关文章
相关标签/搜索