Skip to content

线程同步之os_unfair_lock

pro648 edited this page May 18, 2020 · 1 revision

mind

这是并发控制方案的系列文章,介绍了各种锁的使用及优缺点。

  1. 自旋锁
  2. os_unfair_lock
  3. 互斥锁
  4. 递归锁
  5. 条件锁
  6. 读写锁
  7. @synchronized

OSSpinLock、os_unfair_lock、pthread_mutex_t、pthread_cond_t、pthread_rwlock_t 是值类型,不是引用类型。这意味着使用 = 会进行复制,使用复制的可能导致闪退。pthread 函数认为其一直处于初始化的内存地址,将其移动到其他内存地址会产生问题。使用copy的OSSpinLock不会崩溃,但会得到一个全新的锁。

如果你对线程、进程、串行、并发、并行、锁等概念还不了解,建议先查看以下文章:

os_unfair_lock是一种底层锁,用于取代OSSpinLock,尝试获取已加锁的线程无需忙等,解锁时由内核唤醒。和OSSpinLock一样,os_unfair_lock也没有加强公平性和顺序。例如,释放锁的线程可能立即再次加锁,而之前等待锁的线程唤醒后没有机会尝试加锁。这样有利于提高性能,但也造成了饥饿(starvation)。

Starvation 指贪婪线程占用共享资源太长时间,其他线程无法访问共享资源、无法取得进展。例如,某对象的同步方法占用时间过长,并且频繁调用,其他线程尝试调用该方法时会被堵塞,处于 starvation。

存储在锁中的值应被认为是不透明的,并且在实现中定义。其包含线程信息,系统可用于解决优先级反转问题。

1. 初始化os_unfair_lock

os_unfair_lock结构体包含 unfair lock 数据。

初始化方法如下:

    private var moneyLock: os_unfair_lock = os_unfair_lock_s()
    private var ticketLock: os_unfair_lock = os_unfair_lock_s()

如果在 Objective-C 中使用os_unfair_lock,则应导入#import <os/lock.h>头文件。

2. 加锁os_unfair_lock_lock() os_unfair_lock_trylock()

由于锁的实现依赖锁值和拥有锁进程的地址,因此线程、进程不能通过共享、映射内存地址获取os_unfair_lock

加锁方法如下:

        os_unfair_lock_lock(&moneyLock)

如果锁已经加锁,os_unfair_lock_lock()会休眠,解锁后由内核唤醒。os_unfair_lock_trylock()遇到已经加锁的锁,会直接返回 false。不要在循环中调用os_unfair_lock_trylock()函数,os_unfair_lock_lock()函数已经实现了循环功能。

3. 解锁os_unfair_lock_unlock()

必须在加锁的线程调用os_unfair_lock_unlock()解锁,从其他线程解锁会产生运行时错误。

解锁方法如下:

        os_unfair_lock_unlock(&moneyLock)

完整的代码如下:

class OSUnfairLockDemo: BaseDemo {
    private var moneyLock: os_unfair_lock = os_unfair_lock_s()
    private var ticketLock: os_unfair_lock = os_unfair_lock_s()
    
    override func drawMoney() {
        os_unfair_lock_lock(&moneyLock)
        
        super.drawMoney()
        
        os_unfair_lock_unlock(&moneyLock)
    }
    
    override func saveMoney() {
        os_unfair_lock_lock(&moneyLock)
        
        super.saveMoney()
        
        os_unfair_lock_unlock(&moneyLock)
    }
    
    override func saleTicket() {
        os_unfair_lock_lock(&ticketLock)
        
        super.saleTicket()
        
        os_unfair_lock_unlock(&ticketLock)
    }
}

通常,应优先选择使用高级同步工具。如 pthread、dispatch 等提供的同步方案。

Demo名称:Synchronization
源码地址:https://github.com/pro648/BasicDemos-iOS/tree/master/Synchronization

上一篇:线程同步之自旋锁

下一篇:线程同步之互斥锁

参考资料:

  1. Starvation and Livelock
  2. Synchronization
Clone this wiki locally