美文网首页
iOS 自己实现一个递归自旋锁

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

作者: BossMoney | 来源:发表于2021-08-27 16:54 被阅读0次

    什么是自旋锁?

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

    获取锁的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种锁会造成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。

    相关文章

      网友评论

          本文标题:iOS 自己实现一个递归自旋锁

          本文链接:https://www.haomeiwen.com/subject/dqbmiltx.html