简介: 多核多线程已经成为当下一个时髦的话题,而无锁编程更是这个时髦话题中的热点话题。Linux 内核多是当今最大最复杂的并行程序之一,为咱们分析多核多线程提供了绝佳的范例。内核设计者已经将最新的无锁编程技术带进了 2.6 系统内核中,本文以 2.6.10 版本为基础作相关解释 。html
如何正确有效的保护共享数据是编写并行程序必须面临的一个难题,一般的手段就是同步。同步可分为阻塞型同步(Blocking Synchronization)和非阻塞型同步( Non-blocking Synchronization)。 linux
阻塞型同步是指当一个线程到达临界区时,因另一个线程已经持有访问该共享数据的锁,从而不能获取锁资源而阻塞,直到另一个线程释放锁。常见的同步原语有mutex、semaphore 等。若是同步方案采用不当,就会形成死锁(deadlock),活锁(livelock)和优先级反转(priority inversion),以及效率低下等现象。 为了下降风险程度和提升程序运行效率,业界提出了不采用锁的同步方案,依照这种设计思路设计的算法称为非阻塞型算法,其本质特征就是中止一个线程的执行不会阻碍系统中其余执行实体的运行。 c++
当今比较流行的 Non-blocking Synchronization 实现方案有三种: 算法
1. Wait-free 数据库
Wait-free 是指任意线程的任何操做均可以在有限步以内结束,而不用关心其它线程的执行速度。 Wait-free 是基于 per-thread 的,能够认为是 starvation-free 的。很是遗憾的是实际状况并不是如此,采用 Wait-free 的程序并不能保证 starvation-free,同时内存消耗也随线程数量而线性增加。目前只有极少数的非阻塞算法实现了这一点。 编程
2. Lock-free windows
Lock-Free 是指可以确保执行它的全部线程中至少有一个可以继续往下执行。因为每一个线程不是 starvation-free 的,即有些线程可能会被任意地延迟,然而在每一步都至少有一个线程可以往下执行,所以系统做为一个总体是在持续执行的,能够认为是 system-wide 的。全部 Wait-free 的算法都是 Lock-Free 的。 多线程
3. Obstruction-free less
Obstruction-free 是指在任什么时候间点,一个孤立运行线程的每个操做能够在有限步以内结束。只要没有竞争,线程就能够持续运行。一旦共享数据被修改,Obstruction-free 要求停止已经完成的部分操做,并进行回滚。全部 Lock-Free 的算法都是 Obstruction-free 的。 ide
综上所述,不可贵出 Obstruction-free 是 Non-blocking synchronization 中性能最差的,而 Wait-free 性能是最好的,但实现难度也是最大的,所以 Lock-free 算法开始被重视,并普遍运用于当今正在运行的程序中,好比linux内核。
通常采用原子级的 read-modify-write 原语来实现 Lock-Free 算法,其中 LL 和 SC 是 Lock-Free 理论研究领域的理想原语,但实现这些原语须要 CPU 指令的支持,很是遗憾的是目前没有任何 CPU 直接实现了 SC 原语。根据此理论,业界在原子操做的基础上提出了著名的 CAS(Compare - And - Swap)操做来实现 Lock-Free 算法,Intel 实现了一条相似该操做的指令:cmpxchg8。
CAS 原语负责将某处内存地址的值(1 个字节)与一个指望值进行比较,若是相等,则将该内存地址处的值替换为新值,CAS 操做伪码描述以下:
Bool CAS(T* addr, T expected, T newValue)
{
if( *addr == expected )
{
*addr = newValue;
return true;
}
else
return false;
}
在实际开发过程当中,利用 CAS 进行同步,代码以下所示:
do{ 备份旧数据;
基于旧数据构造新数据;
}while(!CAS( 内存地址,备份的旧数据,新数据 ))
就是指当二者进行比较时,若是相等,则证实共享数据没有被修改,替换成新值,而后继续往下运行;若是不相等,说明共享数据已经被修改,放弃已经所作的操做,而后从新执行刚才的操做。容易看出 CAS 操做是基于共享数据不会被修改的假设,采用了相似于数据库的 commit-retry 的模式。当同步冲突出现的机会不多时,这种假设能带来较大的性能提高。
加锁的层级
根据复杂程度、加锁粒度及运行速度,能够得出以下图所示的锁层级:
其中标注为红色字体的方案为 Blocking synchronization,黑色字体为 Non-blocking
synchronization。Lock-based 和 Lockless-based 二者之间的区别仅仅是加锁粒度的不一样。图中最底层的方案就是你们常用的mutex和 semaphore 等方案,代码复杂度低,但运行效率也最低。
Michael and Scott的伪码:
http://www.cs.rochester.edu/research/synchronization/pseudocode/queues.html
Michael &Scott 无锁队列c++实现(linux下测试经过):
http://www.cnblogs.com/napoleon_liu/archive/2010/08/07/1794566.html
Lock Free Queue implementation in C++ and C#(依赖windows平台):
http://www.codeproject.com/Articles/23317/Lock-Free-Queue-implementation-in-C-and-C