你用过哪些锁?对于锁的种类你了解多少?锁的原理知道否?从本篇博客开始将对锁
的相关内容进行分析!
iOS底层探索之多线程(一)—进程和线程
iOS底层探索之多线程(二)—线程和锁
iOS底层探索之多线程(三)—初识GCD
iOS底层探索之多线程(四)—GCD的队列
iOS底层探索之多线程(五)—GCD不同队列源码分析
iOS底层探索之多线程(六)—GCD源码分析(sync 同步函数、async 异步函数)
iOS底层探索之多线程(七)—GCD源码分析(死锁的原因)
iOS底层探索之多线程(八)—GCD源码分析(函数的同步性、异步性、单例)
iOS底层探索之多线程(九)—GCD源码分析(栅栏函数)
iOS底层探索之多线程(十)—GCD源码分析( 信号量)
iOS底层探索之多线程(十一)—GCD源码分析(调度组)
iOS底层探索之多线程(十二)—GCD源码分析(事件源)
1.锁的介绍
在 iOS 中有以下九种锁
-
OSSpinLock
:(自旋锁) -
dispatch_semaphore_t
:(信号量/互斥锁) -
os_unfair_lock_lock
:(自旋锁) -
pthread_mutex_t
:(互斥递归锁) -
NSLock
:(互斥锁) -
NSCondition
:(条件锁) -
NSRecursiveLock
:(递归锁) -
NSConditionLock
:(条件锁) -
@synchronized
:(内部是互斥锁)
通过对以上的
锁
进行加锁/解锁
10万次的测试表现,结果如下
-
iPhone12 模拟器
-
性能测试统计图表如下
-
iPhoneXR 模拟器
-
iPhoneXR 真机
通过以上测试,锁
的性能最好的前三位是:OSSpinLock
(自旋锁) ->dispatch_semaphone
(信号量) ->pthread_mutex
(互斥锁) ,最差的是synchronized
(互斥锁),但也是我们最常用的锁之一。
2. 锁的分类
锁分为两大类,自旋锁
和互斥锁
。
自旋锁
是一种用于保护多线程共享资源
的锁,与一般互斥锁
(mutex
)不同之处在于当自旋锁尝试获取锁时以忙等待
(busy waiting
)的形式不断地循环检查锁是否可用。当上一个线程的任务没有执行完毕的时候(被锁住),那么下一个线程会一直等待(不会睡眠),当上一个线程的任务执行完毕,下一个线程会立即执行。
在多CPU的环境中,对持有锁较短的程序来说,使用自旋锁代替一般的互斥锁往往能够提高程序的性能。
自旋锁:OSSpinLock(自旋锁)、读写锁
- 自旋锁
- OSSpinLock
- os_unfair_lock_lock
- 互斥锁
- pthread_mutex_t
- NSLock
- NSCondition
- NSRecursiveLock
- NSConditionLock
- dispatch_semaphore_t
- @synchronized (内部是)
互斥锁
当上一个线程的任务没有执行完毕的时候(被锁住),那么下一个线程会进入睡眠状态等待任务执行完毕,当上一个线程的任务执行完毕,下一个线程会自动唤醒然后执行任务,该任务也不会立刻执行,而是成为可执行状态(就绪)。
互斥锁
(mutex),⽤于保证在任何时刻,都只能有⼀个线程访问该对象。
mutex函数
在Posix Thread
中定义有⼀套专⻔⽤于线程同步的mutex
函数。mutex
⽤于保证在任何时刻,都只能有⼀个线程访问该对象。当获取锁操作失败时,线程会进⼊睡眠,等待锁释放时被唤醒。NSLock、NSCondtion、NSRecursiveLock
底层都是对pthread
的封装。
互斥和同步的理解
互斥
:两条线程处理,同一时间只有一个线程可以运行;
同步
:除了有互斥的意思外,同时还有一定的顺序要求,即按照一定的顺序执行。
递归锁
就是同⼀个线程可以加锁N次⽽不会引发死锁NSRecursiveLock、@synchronized、pthread_mutex(recursive)
互斥锁
:pthread_mutex(互斥锁)、@synchronized(互斥锁)、NSLock(互斥锁)
、NSConditionLock(条件锁)
、NSCondition(条件锁)
、NSRecursiveLock(递归锁)
、dispatch_semaphore_t(信号量)
自旋锁和互斥锁的特点
自旋锁
会忙等
,所谓忙等,即在访问被锁资源时,调用者线程不会休眠,而是一直地不停循环在那里,直到被锁资源释放锁,就和上 WC
一样,里面有人了,门锁住了,你一直在门外等着,一直敲门询问
,好了吗?好了没有啊?。
互斥锁
会休眠
,所谓休眠,即在访问被锁资源时,调用者线程会休眠,此时cpu
可以调度其他线程工作,直到被锁资源释放锁,此时会唤醒休眠线程。就是你知道厕所有人了,你先憋着,不会一直敲门询问,等里面的人好了,你在就去。
自旋锁优缺点
优点
在于,因为自旋锁不会引起调用者睡眠,所以不会进行线程调度,CPU
时间片轮转等耗时操作,所有如果能在很短的时间内获得锁,自旋锁
的效率远高于互斥锁
。
缺点
在于,自旋锁一直占用CPU,他在未获得锁的情况下,一直运行自旋,所以占用着CPU,如果不能在很短的时间内获得锁,这无疑会使CPU效率降低。自旋锁不能实现递归调用。
3. 锁的作用
在编程中,特别是多线程开发者中,来保证共享数据
操作的完整性。假如有 ABC三条甚至更多的线程,同时去访问资源,那么读的话是没有问题,要是写的话,就可能出问题,同时修改了某一个数据,这样就破坏的数据的完整性
了。
而加锁
的话,就是同一个时间,只能有一个个线程访问
,其他的靠边等待,可以给每个对象都对应于一个可称为"互斥锁
" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
下篇博客将对锁进行举例并对底层进行分析,敬请期待!
更多内容持续更新
喜欢就点个赞吧
觉得有收获的,可以来一波,收藏+关注,评论 + 转发,以免你下次找不到我
欢迎大家留言交流,批评指正,互相学习,提升自我