iOS线程安全--锁
参考资料:https://developer.aliyun.com/article/1218542?spm=a2c6h.14164896.0.0.70f71fdaogd7rx
NSLock
synchronized闭包
这种锁是比较常用的,因为其使用方法是所有锁中最简单的,但性能却是最差的,所以对性能要求不太高的使用情景下synchronized不失为一种比较方便的锁。代码如下。
NSRecursiveLock
NSRecursiveLock定义了一个锁,该锁可以被同一个线程多次获取而不会导致死锁,死锁是一种线程永久阻塞等待自己放弃锁的情况。当锁定线程有一个或多个锁时,所有其他线程都被阻止访问受该锁保护的代码。
OSSpinLock
自旋锁:由于一直处于while循环,所以对CPU的占用也是比较高的,用CPU的消耗换来的好处就是自旋锁的性能很高。系统维护了 5 个不同的线程优先级/QoS: background,utility,default,user-initiated,user-interactive。高优先级线程始终会在低优先级线程前执行,一个线程不会受到比它更低优先级线程的干扰。这种线程调度算法会产生潜在的优先级反转问题,从而破坏了 spin lock。
具体来说,如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放 lock。这并不只是理论上的问题,libobjc 已经遇到了很多次这个问题了,于是苹果的工程师停用了 OSSpinLock。
优先级高的持续占有cpu,直到获取到资源。低优先级的竞争不过cpu,但是拿着资源,无法使用。导致死锁。
dispatch_semaphore
在iOS开发中,信号量就是通过GCD来实现的,而GCD是对C语言的一个封装,不同的开发语言中对于信号量semaphore都有自己的实现,所以本节不仅是代表了pthread,也是信号量的使用,更是跨线程访问的一个主要的知识点。
信号量的使用其实很简单,与其他开发语言中使用的信号量类似,通过对信号的等待和释放来使用,信号量属于生产者消费者模式,这种模式可以用在多个使用场景中,下面只是比较常见的一种。
dispatch_semaphore_create(1)
dispatch_semaphore_wait()
dispatch_semaphore_signal()
NSConditionLock与NSCondition
状态锁是一种比较常用的锁,在多线程操作中,用户可以指定某线程去执行操作,只需要设定对应的状态即可。
pthread
pthread的全称是POSIX thread,是一套跨平台的多线程API,各个平台对其都有实现。pthread是一套非常强大的多线程锁,可以创建互斥锁(普通锁)、递归锁、信号量、条件锁、读写锁、once锁等,基本上所有涉及的锁,都可以用pthread来实现,下面分别对其进行举例。
1.互斥锁(普通锁)
pthread_mutex_unlock
pthread_mutex_lock
2.递归锁
递归锁的创建方法跟普通锁是同一个方法,不过需要传递一个attr参数。
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
3.pthread信号量
pthread的信号量不同于GCD自带的信号量,如前面所说,pthread是跨平台多线程处理的API,对信号量处理也提供了相应的使用。其大概原理和使用方法与GCD提供的信号量机制类似,使用起来也比较方便。关于GCD的信号量在下面会单独讲到,这里是pthread信号量的使用代码。
4.读写锁
读写锁是一种特殊的自旋锁,将对资源的访问者分为读者和写者,顾名思义,读者对资源只进行读访问,而写者对资源只有写访问。相对于自旋锁来说,这种锁能提高并发性。在多核处理器操作系统中,允许多个读者访问同一资源,却只能有一个写者执行写操作,并且读写操作不能同时执行。
pthread_rwlock_rdlock
pthread_rwlock_unlock
5.信号量。。。。。
网友评论