iOS底层探索之多线程(十三)—锁的种类你知多少?

你用过哪些锁?对于锁的种类你了解多少?锁的原理知道否?从本篇博客开始将对的相关内容进行分析!

关于锁你知多少?.png

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 中有以下九种锁

  1. OSSpinLock:(自旋锁)
  2. dispatch_semaphore_t:(信号量/互斥锁)
  3. os_unfair_lock_lock:(自旋锁)
  4. pthread_mutex_t:(互斥递归锁)
  5. NSLock:(互斥锁)
  6. NSCondition:(条件锁)
  7. NSRecursiveLock:(递归锁)
  8. NSConditionLock:(条件锁)
  9. @synchronized:(内部是互斥锁)

通过对以上的进行 加锁/解锁 10万次的测试表现,结果如下

  1. iPhone12 模拟器


    iPhone12 模拟器
  • 性能测试统计图表如下


    iPhone12 模拟器
  1. iPhoneXR 模拟器


    iPhoneXR 模拟器
  2. iPhoneXR 真机

    iPhoneXR 真机

    通过以上测试,的性能最好的前三位是:OSSpinLock(自旋锁) -> dispatch_semaphone(信号量) -> pthread_mutex(互斥锁) ,最差的是synchronized(互斥锁),但也是我们最常用的锁之一。

2. 锁的分类

锁分为两大类,自旋锁互斥锁

自旋锁

是一种用于保护多线程共享资源的锁,与一般互斥锁mutex)不同之处在于当自旋锁尝试获取锁时以忙等待busy waiting)的形式不断地循环检查锁是否可用。当上一个线程的任务没有执行完毕的时候(被锁住),那么下一个线程会一直等待(不会睡眠),当上一个线程的任务执行完毕,下一个线程会立即执行。
在多CPU的环境中,对持有锁较短的程序来说,使用自旋锁代替一般的互斥锁往往能够提高程序的性能。

自旋锁:OSSpinLock(自旋锁)、读写锁

  1. 自旋锁
  • OSSpinLock
  • os_unfair_lock_lock
  1. 互斥锁
  • 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三条甚至更多的线程,同时去访问资源,那么读的话是没有问题,要是写的话,就可能出问题,同时修改了某一个数据,这样就破坏的数据的完整性了。

加锁的话,就是同一个时间,只能有一个个线程访问,其他的靠边等待,可以给每个对象都对应于一个可称为"互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

下篇博客将对锁进行举例并对底层进行分析,敬请期待!

更多内容持续更新

喜欢就点个赞吧

觉得有收获的,可以来一波,收藏+关注,评论 + 转发,以免你下次找不到我

欢迎大家留言交流,批评指正,互相学习,提升自我

你可能感兴趣的:(iOS底层探索之多线程(十三)—锁的种类你知多少?)