无并发,不编程.提到多线程就很难绕开锁?.

iOS开发中较常见的两类锁:

1. 互斥锁: 同一时刻只能有一个线程获得互斥锁,其余线程处于挂起状态.
2. 自旋锁: 当某个线程获得自旋锁后,别的线程会一直做循环,尝试加锁,当超过了限定的次数仍然没有成功获得锁时,线程也会被挂起.

自旋锁较适用于锁的持有者保存时间较短的情况下,实际使用中互斥锁会用的多一些.

1. 互斥锁,信号量

1.遵守NSLocking协议的四种锁

四种锁分别是:
NSLockNSConditionLockNSRecursiveLockNSCondition

NSLocking协议

public protocol NSLocking {    public func lock()public func unlock()
}
复制代码

下面举个多个售票点同时卖票的例子

var ticket = 20
var lock = NSLock()override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {let thread1 = Thread(target: self, selector: #selector(saleTickets), object: nil)thread1.name = "售票点A"thread1.start()let thread2 = Thread(target: self, selector: #selector(saleTickets), object: nil)thread2.name = "售票点B"thread2.start()
}@objc private func saleTickets() {while true {lock.lock()Thread.sleep(forTimeInterval: 0.5) // 模拟延迟if ticket > 0 {ticket = ticket - 1print("\(String(describing: Thread.current.name!)) 卖出了一张票,当前还剩\(ticket)张票")lock.unlock()}else {print("oh 票已经卖完了")lock.unlock()break;}}
}
复制代码

遵守协议后实现的两个方法lock()unlock(),意如其名.

除此之外NSLockNSConditionLockNSRecursiveLockNSCondition四种互斥锁各有其实现:

1. 除NSCondition外,三种锁都有的两个方法:
    // 尝试去锁,如果成功,返回true,否则返回falseopen func `try`() -> Bool// 在limit时间之前获得锁,没有返回NOopen func lock(before limit: Date) -> Bool
复制代码
2. NSCondition条件锁:
    // 当前线程挂起open func wait()// 当前线程挂起,设置一个唤醒时间open func wait(until limit: Date) -> Bool// 唤醒在等待的线程open func signal()// 唤醒所有NSCondition挂起的线程open func broadcast()
复制代码

当调用wait()之后,NSCondition实例会解锁已有锁的当前线程,然后再使线程休眠,当被signal()通知后,线程被唤醒,然后再给当前线程加锁,所以看起来好像wait()一直持有该锁,但根据苹果文档中说明,直接把wait()当线程锁并不能保证线程安全.

3. NSConditionLock条件锁:

NSConditionLock是借助NSCondition来实现的,在NSCondition的基础上加了限定条件,可自定义程度相对NSCondition会高些.

    // 锁的时候还需要满足conditionopen func lock(whenCondition condition: Int)// 同try,同样需要满足conditionopen func tryLock(whenCondition condition: Int) -> Bool// 同unlock,需要满足conditionopen func unlock(withCondition condition: Int)// 同lock,需要满足condition和在limit时间之前open func lock(whenCondition condition: Int, before limit: Date) -> Bool
复制代码
4. NSRecurisiveLock递归锁:

定义了可以多次给相同线程上锁并不会造成死锁的锁.

提供的几个方法和NSLock类似.

2. GCD的DispatchSemaphore和栅栏函数
1. DispatchSemaphore信号量:

DispatchSemaphore中的信号量,可以解决资源抢占的问题,支持信号的通知和等待.每当发送一个信号通知,则信号量+1;每当发送一个等待信号时信号量-1,如果信号量为0则信号会处于等待状态.直到信号量大于0开始执行.所以我们一般将DispatchSemaphore的value设置为1.

下面给出了DispatchSemaphore的封装类

class GCDSemaphore {// MARK: 变量fileprivate var dispatchSemaphore: DispatchSemaphore!// MARK: 初始化public init() {dispatchSemaphore = DispatchSemaphore(value: 0)}public init(withValue: Int) {dispatchSemaphore = DispatchSemaphore(value: withValue)}// 执行public func signal() -> Bool {return dispatchSemaphore.signal() != 0}public func wait() {_ = dispatchSemaphore.wait(timeout: DispatchTime.distantFuture)}public func wait(timeoutNanoseconds: DispatchTimeInterval) -> Bool {if dispatchSemaphore.wait(timeout: DispatchTime.now() + timeoutNanoseconds) == DispatchTimeoutResult.success {return true} else {return false}}
}
复制代码
2. barrier栅栏函数:

栅栏函数也可以做线程同步,当然了这个肯定是要并行队列中才能起作用.只有当当前的并行队列执行完毕,才会执行栅栏队列.

/// 创建并发队列
let queue = DispatchQueue(label: "queuename", attributes: .concurrent)
/// 异步函数
queue.async {for _ in 1...5 {print(Thread.current)}
}
queue.async {for _ in 1...5 {print(Thread.current)}
}
/// 栅栏函数
queue.async(flags: .barrier) {print("barrier")
}
queue.async {for _ in 1...5 {print(Thread.current)}
}
复制代码
3. 其他的互斥锁
1. pthread_mutex互斥锁

pthread表示POSIX thread,跨平台的线程相关的API,pthread_mutex也是一种互斥锁,互斥锁的实现原理与信号量非常相似,阻塞线程并睡眠,需要进行上下文切换.

一般情况下,一个线程只能申请一次锁,也只能在获得锁的情况下才能释放锁,多次申请锁或释放未获得的锁都会导致崩溃.假设在已经获得锁的情况下再次申请锁,线程会因为等待锁的释放而进入睡眠状态,因此就不可能再释放锁,从而导致死锁.

这边给出了一个基于pthread_mutex_t(安全的"FIFO"互斥锁)的封装 MutexLock

1. @synchronized条件锁

日常开发中最常用的应该是@synchronized,这个关键字可以用来修饰一个变量,并为其自动加上和解除互斥锁.这样,可以保证变量在作用范围内不会被其他线程改变.但是在swift中它已经不存在了.其实@synchronized在幕后做的事情是调用了objc_sync中的objc_sync_enterobjc_sync_exit 方法,并且加入了一些异常判断.

因此我们可以利用闭包自己封装一套.

func synchronized(lock: AnyObject, closure: () -> ()) {objc_sync_enter(lock)closure()objc_sync_exit(lock)
}// 使用
synchronized(lock: AnyObject) {// 此处AnyObject不会被其他线程改变
}复制代码

2. 自旋锁

1. OSSpinLock自旋锁

OSSpinLock是执行效率最高的锁,不过在iOS10.0以后已经被废弃了.

详见大神ibireme的不再安全的 OSSpinLock

2. os_unfair_lock自旋锁

它能够保证不同优先级的线程申请锁的时候不会发生优先级反转问题.这是苹果为了取代OSSPinLock新出的一个能够避免优先级带来的死锁问题的一个锁,OSSPinLock就是有由于优先级造成死锁的问题.

注意: 这个锁适用于小场景下的一个高效锁,否则会大量消耗cpu资源.

var unsafeMutex = os_unfair_lock()
os_unfair_lock_lock(&unsafeMutex)
os_unfair_lock_trylock(&unsafeMutex)
os_unfair_lock_unlock(&unsafeMutex)
复制代码

这边给出了基于os_unfair_lock的封装 MutexLock

3. 性能比较

这边贴一张大神ibireme在iPhone6、iOS9对各种锁的性能测试图

本文收录于 SwiftTips

参考:
不再安全的OSSpinLock
深入理解iOS开发中的锁

如有疑问,欢迎留言 :-D

线程安全: 互斥锁和自旋锁(10种)相关推荐

  1. epoll的具体实现与epoll线程安全,互斥锁,自旋锁,CAS,原子操作

    互斥锁,自旋锁,原子操作,CAS 1. 互斥锁的原理 2. 自旋锁的使用场景 3. 三种操作的使用场景与区别 [技术分享篇]epoll的具体实现与epoll线程安全,互斥锁,自旋锁,CAS,原子操作 ...

  2. 互斥锁、自旋锁和自适应自旋锁

    互斥锁: 从 实现原理上来讲,Mutex属于sleep-waiting类型的锁.例如在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在Core0和 Core1上.假设线程A想要通过pthr ...

  3. 漫画Linux 并发、竞态、互斥锁、自旋锁、信号量

    1. 锁的由来? 学习linux的时候,肯定会遇到各种和锁相关的知识,有时候自己学好了一点,感觉半桶水的自己已经可以华山论剑了,又突然冒出一个新的知识点,我看到新知识点的时候,有时间也是一脸的懵逼,在 ...

  4. Linux C/C++ 并发下的技术方案(互斥锁、自旋锁、原子操作)

    前言 线程:是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务.在Uni ...

  5. Java中的锁机制 -- 乐观锁、悲观锁、自旋锁、可重入锁、读写锁、公平锁、非公平锁、共享锁、独占锁、重量级锁、轻量级锁、偏向锁、分段锁、互斥锁、同步锁、死锁、锁粗化、锁消除

    文章目录 1. Java中的锁机制 1.1 乐观锁 1.2 悲观锁 1.3 自旋锁 1.4 可重入锁(递归锁) 1.5 读写锁 1.6 公平锁 1.7 非公平锁 1.8 共享锁 1.9 独占锁 1.1 ...

  6. java锁(公平锁和非公平锁、可重入锁(又名递归锁)、自旋锁、独占锁(写)/共享锁(读)/互斥锁、读写锁)

    前言 本文对Java的一些锁的概念和实现做个整理,涉及:公平锁和非公平锁.可重入锁(又名递归锁).自旋锁.独占锁(写)/共享锁(读)/互斥锁.读写锁 公平锁和非公平锁 概念 公平锁是指多个线程按照申请 ...

  7. Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等...

    http://blog.51cto.com/13919357/2339446 Java 中15种锁的介绍 在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容 ...

  8. 华为应用锁退出立即锁_面试官:你说说互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景...

    前言 生活中用到的锁,用途都比较简单粗暴,上锁基本是为了防止外人进来.电动车被偷等等. 但生活中也不是没有 BUG 的,比如加锁的电动车在「广西 - 窃·格瓦拉」面前,锁就是形同虚设,只要他愿意,他就 ...

  9. 信号量、互斥体和自旋锁

    一.信号量 信号量又称为信号灯,它是用来协调不同进程间的数据对象的,而最主要的应用是共享内存方式的进程间通信.本质上,信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况.一般说来,为了获 ...

最新文章

  1. CentOS 6.5 apache源码安装2.0版
  2. 单价数量和总价的公式_小学六年超全的数学公式!家长们赶紧给孩子看过来……...
  3. Unity3D笔记 愤怒的小鸟六 弹弓发射小鸟
  4. STM32 基础系列教程 40 - Lwip_mqtt
  5. 《Humans vs Computers》作者访谈录
  6. 最值钱无人车团队组织架构曝光:Waymo总共不到千人,2/3是工程师
  7. 跨部门的bug的沟通
  8. SSIM和PSNR计算
  9. 房地产大数据分析方法
  10. 区块链电子证据的司法应用现状与展望
  11. ArcGIS Pro地理配准
  12. 雪人(snowman)
  13. 阻挡前进的小兵<隐私政策>
  14. 浮点运算单元FPU能给电机控制带来什么?
  15. 适用于计量站电子测量仪器自动检定系统设计
  16. CSDN博客如何改名字
  17. 2021-05-08 小华子第一篇
  18. 互联网呼唤版权社会化服务
  19. [pytorch] PyTorch Metric Learning库代码学习二 Inference
  20. 如何快速实现离散企业全链路数字化管理?

热门文章

  1. struts2相对路径解释
  2. Behavior Trees
  3. Codeforces Round #309 (Div. 2) A. Kyoya and Photobooks 字符串水题
  4. 快快: 一点即玩的游戏客户端平台
  5. IP修改器的作用以及用途
  6. .net工具类 分享一个简单的随机分红包的实现方式
  7. Java反射在整个程序运行中的位置
  8. 微信OAuth2网页授权登陆接口
  9. Java 文件上传下载管理器(控制台)
  10. shell脚本监控系统负载、CPU和内存使用情况