几种锁算法的实现



Multicore

Abstract

4种Lock的实现:

  • TASLock
  • TTASLock
  • CLHLock
  • MCSLock

TASLock

每一个Lock带有一个状态位,lock()与unlock()操作原子的改变状态位。
false时可进入,true时spin。

public class TASLock implements Lock
{
    AtomicBoolean state = new AtomicBoolean(false);
    public void lock()
    {
        while(state.getAndSet(true))
        {}
    }

    public void unlock()
    {
        state.set(false);
    }
}

defect:

  • 在锁被其他线程持有的情况下,while(state.getAndSet(true))会不停的将
    state从true改为true

TTASLock

TASLock算法的改进。

public class TTASLock implements Lock()
{
    AtomicBoolean state = new AtomicBoolean(false);
    public void lock()
    {
        while (true)
        {
            while (state.get())
            {};
            if (! state.getAndSet(true))
                return;
        }
    }

    public void unlock()
    {
        state.set(false);
    }
}
  1. while (state.get()){}是一个改进,效果是先看一眼lock的状态,当lock是false时,
    再真正的执行state.getAndSet(true)
  2. 当state.getAndSet(true) 的return为false时,说明之前的确是false,于是获得锁,return。
    否则回到while(true),再次尝试获得锁。
defect:
  • 在unlock时,state.set(false)还是会带来大量的cache miss。
  • cache miss VS cache hit

CLHLock

队列锁。
CLHLock

void initCLHlock()
{
    q.locked = FALSE;
    tail = &q;
}

void lock()
{

    QNode* qnode = (QNode*)pthread_getspecific(myNode);
    qnode->locked = TRUE;
    QNode* pred = getAndSet(qnode);//原子的得到队尾,并将qnode设为新的队尾。
    pthread_setspecific(myPred, pred);


    while(pred->locked)
    {
    }

}


void unlock()
{
    QNode* qnode = (QNode*)pthread_getspecific(myNode);
    qnode->locked = FALSE;
    QNode* pred = (QNode*)pthread_getspecific(myPred);
    pthread_setspecific(myNode, pred);//unlock时必须将myNode指向前面的Node
}
NOTE:
  • unlock时必须将myNode指向前面的Node!
    后果:如果Thread A unlock()后,紧接着又进入
    队尾, A的locked会再次被置为TRUE, Thread B还在看着Thread A 的locked字段,于是产生
    deadlock。
  • 初始时教室里面有一个空凳子, 每个学生来到门口排队时都自己带着一个凳子。

MCSLock

public class MCSLock implements Lock
{
    AtomicReference<QNode> tail;
    ThreadLocal<QNode> myNode;
    public MCSLock()
    {
        queue = new AtomicReference<QNode>(null);
        myNode = new ThreadLocal<QNode>()
        {
            protected QNode initialValue()
            {
                return new QNode();
            }
        };
    }
    ...
    class QNode
    {
        boolean locked = false;
        QNode next = null;//与CLHLock相比,多了这个真正的next
    }
}   

public void lock()
{
    QNode qnode = myNode.get();
    QNode pred = tail.getAndSet(qnode);
    if (pred != null)
    {
        qnode.locked = true;
        pred.next = qnode;
        //wait until predecessor gives up the lock
        while(qnode.locked){}//将自己设为true然后spin,看似deadlock
    }
}
public void unlock()
{
    QNode qnode = myNode.get();
    if (qnode.next == null)         //后面没有等待线程的情况
    {//------there is a gap!!!!
        if (tail.compareAndSet(qnode, null))
            return;                 //真的没有等待线程,则直接返回,不需要通知
        //wait until predecessor fills in its next field
        while (qnode.next == null){}
    }
    //右面有等待线程,则通知后面的线程
    qnode.next.locked = false;
    qnode.next = null;
}
NOTE:
  • unlock()要要特别的注意。

Summary

  • CLHLock的思想是当前线程在前一个线程的node上spin,每个线程unlock时修改自身的标记。
    在共享总线结构下性能可以,无法应对分布式。
  • MCSLock 用于解决分布式并行的问题。每个线程都在自己的node上spin,当释放锁时通知
    后面的线程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值