iOS 自己实现一个递归自旋锁

2021-08-27  本文已影响0人  BossMoney

什么是自旋锁?

是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成busy-waiting,这样会使cpu资源浪费。所以自旋锁一般使用在加锁代码段执行耗时非常短的地方。

使用swift实现一个自旋锁

public class BMLock {
    private var locked = 0
    
    func lock() {
        while !OSAtomicCompareAndSwapLongBarrier(0, 1, &locked) {}
    }
    
    func unlock() {
        OSAtomicCompareAndSwapLongBarrier(1, 0, &locked)
    }
}
func OSAtomicCompareAndSwapLongBarrier(_ __oldValue: Int, _ __newValue: Int, _ __theValue: UnsafeMutablePointer<Int>!) -> Bool

这里使用了CompareAndSet(CAS)。
伪代码是这样的

func OSAtomicCompareAndSwapLongBarrier(_ __oldValue: Int, _ __newValue: Int, _ __theValue: Int) -> Bool {
        if oldValue == theValue {
            theValue = newValue
            return true
        } else {
            return false
        }
}

如果需要递归

public class BMLock {
    
    private var thread:UnsafeMutableRawPointer?
    private var count = 0
    
    public func lock() {
        if OSAtomicCompareAndSwapPtrBarrier(pthread_self(), pthread_self(), &thread) {
            count += 1
            return
        }
        while !OSAtomicCompareAndSwapPtrBarrier(nil, pthread_self(), &thread) {usleep(10)}//usleep10提高性能
    }
    
    public func unlock() {
        if count > 0 {
            count -= 1
        } else {
            OSAtomicCompareAndSwapPtrBarrier(pthread_self(), nil, &thread)
        }
    }
    
}

CompareAndSet通过原子操作实现了CAS操作,最底层基于汇编语言实现。

简单说一下原子操作的概念,“原子”代表最小的单位,所以原子操作可以看做最小的执行单位,该操作在执行完毕前不会被任何其他任务或事件打断。

这里还需要使用带barrier结尾的方法。

Memory ordering

Memory ordering用来描述系统中的processor对内存的操作如何对其它processor可见(可见的定义见前面的描述)。同时需要说明的是,大多数文献都采用reorder这个表达方式,是从执行等价的角度来描述的:比如P1上执行两个写操作WRITE(A)和WRITE(B),如果对于观察者P2来说P1|WRITE(B)先于P2|WRITE(A)可见,那么就可以认为P1的写操作发生了reorder。对读操作也是类似的。
影响memoryordering的因素很多,包括:
体系结构,X86和ARM的memory ordering就截然不同;
ARM的memory order属于weak order,与SC差距极大。如果涉及到免锁设计,对ARM体系结构, memorybarrier的使用是不可避免的。

自旋锁缺点

自旋锁会存在优先级反转问题。
具体来说,如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放 lock。

苹果的OSSpinLock因为存在优先级反转问题,在 iOS 10/macOS 10.12 发布时,苹果提供了新的 os_unfair_lock 作为 OSSpinLock 的替代,并且将 OSSpinLock 标记为了 Deprecated。

上一篇下一篇

猜你喜欢

热点阅读