本文博主带领大家一起学习一下iOS开发中的锁。


为什么用到锁?

当一个线程访问数据的时候,其他的线程不能对其进行访问,直到该线程访问完毕。即确保线程安全。比如:iOS中的读写文件,当一个线程在写文件时,如果另一个线程去读或者去写,这样都会导致数据紊乱。为了线程安全,我们使用锁的机制来确保,同一时刻只有同一个线程来对一个数据源进行访问。

iOS中都用什么锁?

ios while 卡线程 ios开发线程锁_ios while 卡线程

互斥锁

1.NSLock 
	2.pthread_mutex
	3.@synchronized
	4.os_unfair_lock

是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制。该目的通过将代码切片成一个一个的临界区而达成。

自旋锁

1.OSSpinLock

是用于多线程同步的一种锁,线程反复检查锁变量是否可用。由于线程在这一过程中保持执行,因此是一种忙等待。一旦获取了自旋锁,线程会一直保持该锁,直至显式释放自旋锁。 自旋锁避免了进程上下文的调度开销,因此对于线程只会阻塞很短时间的场合是有效的。

自旋锁和互斥锁的区别对比:
自旋锁的效率高于互斥锁
相同点:
都能保证同一时间只有一个线程访问共享资源,都能保证线程安全。
不同点:
互斥锁:如果共享数据已经有其他线程加锁了,线程会进入休眠状态等待锁,一旦被访问的资源被解锁,则等待资源的线程会被唤醒。
自旋锁:如果共享数据已经有其他线程加锁了,线程会以死循环的方式等待锁,一旦被访问的资源被解锁,则等待资源的线程会立即执行。

递归锁

1.NSRecursiveLock:
2.pthread_mutex

递归锁有一个特点,就是同一个线程可以加锁N次而不会引发死锁。

条件锁

1. NSCondition:
2.NSConditionLock:

就是条件变量,当进程的某些资源要求不满足时就进入休眠,也就是锁住了。当资源被分配到了,条件锁打开,进程继续运行。

读写锁

pthread_rwlock
读写锁通常用互斥锁、条件变量、信号量实现。

是计算机程序的并发控制的一种同步机制,也称“共享-互斥锁”、多读者-单写者锁) 用于解决多线程对公共资源读写问题。读操作可并发重入,写操作是互斥的。

信号量

1. dispatch_semaphore

遵循NSLocking协议,使用的时候同样是lock,unlock加解锁,wait是傻等,waitUntilDate:方法是等一会,都会阻塞掉线程,signal是唤起一个在等待的线程,broadcast是广播全部唤起。

1.NSLock

NSLock实现了最基本的互斥锁,使用时需要遵循 NSLocking协议,通过lock和unlock来进行锁定和解锁。

例子如下:在线程A 调用unlock方法之前,另一个线程B调用了同一锁对象的lock方法。那么,线程B只有等待。直到线程A调用了unlock。

实际项目中:NSLock在AFNetworking的AFURLSessionManager.m中应用如下:

ios while 卡线程 ios开发线程锁_ios开发_02

ios while 卡线程 ios开发线程锁_自旋锁_03


2.@synchronized

实际项目中:AFNetworking中 isNetworkActivityOccurring属性的getter方法

ios while 卡线程 ios开发线程锁_ios开发_04

3.dispatch_semaphore

dispatch_semaphore是GCD用来同步的一种方式,与他相关的共有三个函数,分别是:

dispatch_semaphore_create(创建一个semaphore),dispatch_semaphore_signal(发送一个信号),dispatch_semaphore_wait(等待信号)。

dispatch_semaphore在YYKit中的YYThreadSafeArray.m有所应用

ios while 卡线程 ios开发线程锁_ios while 卡线程_05


这个例子中,为线程设置了最大等待时间12秒,所以当上面的线程sleep10秒的时候,下面的线程仍然要等待。4.phtread_mutex

phtread_mutex实现互斥锁比递归锁效率高。

在YYKit的YYMemoryCach中可以看到

ios while 卡线程 ios开发线程锁_互斥锁_06


5.pthread_rwlock

//加读锁
pthread_rwlock_rdlock(&rwlock);
//解锁
pthread_rwlock_unlock(&rwlock);
//加写锁
pthread_rwlock_wrlock(&rwlock);
//解锁
pthread_rwlock_unlock(&rwlock);

6.NSCondition

ios while 卡线程 ios开发线程锁_互斥锁_07

代码分析:condition 进入到判断条件中,当products == 0 的时候,condition 调用wait 时当前线程处于等待状态;其他线程开始访问products,当NSObject 创建完成并加入到products时,cpu发出single的信号时,处于等待的线程被唤醒,开始执行[products removeObjectAtIndex:0];

7.OSSpinLock
首先要提的是OSSpinLock已经出现了BUG,导致并不能完全保证是线程安全的。
8.os_unfair_lock
os_unfair_lock 是苹果官方推荐的替换OSSpinLock的方案,它是一个互斥锁,但是它在iOS10.0以上的系统才可以调用。os_unfair_lock是一种互斥锁,它不会向自旋锁那样忙等,而是等待线程会休眠。

9.NSConditionLock
NSConditionLock定义了一个可以指定条件的互斥锁,用于线程之间的互斥与同步,性能较低。
10.NSRecursiveLock
NSRecursiveLock在YYKit中YYWebImageOperation.m中有用到