下面是各种线程锁的效率,当然这个结果只能当做一个定性分析,根据实现原理的不用,这些形形色色的锁再不同场景下可以发挥其独有的作用。
自旋锁:当一个线程上锁之后,其他线程再次访问会一直循环查看该锁是否被释放,因为忙等会消耗大量CPU资源,但是不涉及到操作系统上下文的切换,所以该锁适用于锁的持有者保存时间较短的情况,例如内存缓存的存取。
解释:
线程一直running(加锁-->解锁),死循环(do-while等待)检测锁的标志位,机制比较简单。也正因为do-while所以会占用CPU时间,消耗CPU资源较多。
由于OSSpinLock存在优先级反转的问题,也就是低优先级的线程1获得锁并访问共享资源,高优先级的线程2也想访问共享资源,则线程2处于自旋锁忙等状态从而占用大量CPU资源,而低优先级线程无法与高优先级线程争夺CPU资源,导致线程1迟迟不能完成。所以苹果又出了个os_unfair_lock_t
详见YY大神 不再安全的 OSSpinLock
用法:
os_unfair_lock_t lock = &(OS_UNFAIR_LOCK_INIT);
os_unfair_lock_lock(lock);
os_unfair_lock_unlock(lock);
原理:(伪代码如下)
bool lock = false;
do{
while(lock);//如果上锁循环等待。这里lock的存取是具有原子性的。
lock = true;//上锁
Critical section//临界区,需要保护的代码。
lock = false;//解锁
Reminder section // 不需要锁保护的代码
}
信号量(dispatch_semaphore):当信号量值大于0,该函数所处线程就继续执行下面的语句,当信号量值小于0,会阻塞当前线程。相关方法:dispatch_semaphore_wait(-1)、dispatch_semaphore_signal(+1)。
解释:
当dispatch_semaphore_wait判断小于0的时候,当前线程会主动让出时间片,由于让出时间片会导致操作系统切到其他线程,这种上下文切换通常需要10微秒的时间,而且至少要切换两次。所以等待时间短频繁切换的情况下他并不适用。
pthread_mutex:互斥锁的实现原理和信号量非常相似,不用忙等,而是阻塞线程,需要上下文切换。
解释:
存在三种类型 PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、PTHREAD_MUTEX_RECURSIVE等等,这也是为什么它的性能相比于信号量略低。
使用:
#import <pthread.h>//引用
pthread_mutex_t pMutex;//申明
pthread_mutex_init(&pMutex,NULL);//初始化
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); // 定义锁的属性、有很多种类型,如递归锁等
pthread_mutex_lock(&pMutex);//获得锁
pthread_mutex_unlock(&pMutex);//解锁
网友评论