首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

线程锁系列(一):CLH Lock

2012-12-23 
线程锁系列(1):CLH Lock?最近在看关于线程锁的算法,做一个整理。资料出自于《The Art of Multiprocessor Pro

线程锁系列(1):CLH Lock

?

最近在看关于线程锁的算法,做一个整理。资料出自于《The Art of Multiprocessor Programming》,算是一个读书笔记吧。示范代码基于java。

第一章是Craig, Landin, and Hagersten (CLH) locks。先上CLHLock的实现逻辑:

public class CLHLock implements Lock {    private final AtomicReference tail;    private final ThreadLocal myPred;    private final ThreadLocal myNode;    public CLHLock() {        tail = new AtomicReference(new QNode());        myNode = new ThreadLocal() {            protected QNode initialValue() {                return new QNode();            }        };        myPred = new ThreadLocal();    }    @Override    public void lock() {        QNode node = myNode.get();        node.locked = true;        QNode pred = tail.getAndSet(node);        myPred.set(pred);        while (pred.locked) {        }    }    @Override    public void unlock() {        QNode node = myNode.get();        node.locked = false;        myNode.set(myPred.get());    }    private static class QNode {        volatile boolean locked;    }}



CLH Lock是一个自旋锁,能确保无饥饿性,提供先来先服务的公平性。

?

锁本身被表示成QNode的虚拟链表。共享的tail保存申请的最后的一个申请lock的线程的myNode域。每个申请lock的线程通过一个本地线程变量pred指向它的前驱。另外一个本地线程变量myNode的locked保存本身的状态,true:正在申请锁或已申请到锁;false:已释放锁。每个线程通过监视自身的前驱状态,自旋等待锁被释放。释放锁时,把自身myNode的locked设为false,使后继线程获的锁,并回收前驱的QNode,等待下次使用,因为自身的QNode可能被tail获后继引用,而前驱不再使用老的QNode。

?

该算法也是空间有效的,如果有n个线程,L个锁,每个线程每次只获取一个锁,那么需要的存储空间是O(L+n),n个线程有n个myNode,L个锁有L个tail。这种算法有一个缺点是在NUMA系统架构下性能表现很差,因为它自旋的locked是前驱线程的,如果内存位置较远,那么性能会受到损失。但是在SMP这种cache一致性的系统架构上表现良好。

?

下一章会整理MCSLock,它更适用于NUMA架构。

?

热点排行