iOS 中的各种锁
简单的性能测试
互斥锁
1.NSLock:是Foundation框架中以对象形式暴露给开发者的一种锁
缺点:多次lock会造成线程死锁。
2.pthread_mutex
3.@synchronized:
实际项目中:AFNetworking中 isNetworkActivityOccurring属性的getter方法
- (BOOL)isNetworkActivityOccurring {
@synchronized(self) {
return self.activityCount > 0;
}
}
自旋锁
1.OSSpinLock:
OSSpinLock lock = OS_SPINLOCK_INIT;
OSSpinLockLock(&lock);
...
OSSpinLockUnlock(&lock);
上面是OSSpinLock使用方式,编译会报警告,已经废弃了,OSSpinLock大家也已经不再用它了,因为它在某一些场景下已经不安全了,可以参考 YY大神的不再安全的 OSSpinLock,在Protocol Buffers项目中你可以看到这样的注释,大家已经用新的方案替换了。
// NOTE:OSSpinLock may seem like a good fit here but Apple engineers have// pointed out that they are vulnerable to live locking on iOS in cases of// priority inversion:// http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/// https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html
2.os_unfair_lock:
os_unfair_lock 是苹果官方推荐的替换OSSpinLock的方案,但是它在iOS10.0以上的系统才可以调用。
os_unfair_lock_t unfairLock;
unfairLock = &(OS_UNFAIR_LOCK_INIT);
os_unfair_lock_lock(unfairLock);
os_unfair_lock_unlock(unfairLock);
读写锁
上文有说到,读写锁又称共享-互斥锁,
pthread_rwlock:
//加读锁
pthread_rwlock_rdlock(&rwlock);
//解锁
pthread_rwlock_unlock(&rwlock);
//加写锁
pthread_rwlock_wrlock(&rwlock);
//解锁
pthread_rwlock_unlock(&rwlock);
递归锁
递归锁有一个特点,就是同一个线程可以加锁N次而不会引发死锁。
1.NSRecursiveLock:
NSRecursiveLock在YYKit中YYWebImageOperation.m中有用到:
_lock = [NSRecursiveLock new];
- (void)dealloc {
[_lock lock];
...
...
[_lock unlock];
}
2.pthread_mutex(recursive):
pthread_mutex锁也支持递归,只需要设置PTHREAD_MUTEX_RECURSIVE即可
pthread_mutex_t lock;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&lock, &attr);
pthread_mutexattr_destroy(&attr);
pthread_mutex_lock(&lock);
pthread_mutex_unlock(&lock);
条件锁
1.NSCondition:
定义:
@interface NSCondition : NSObject <NSLocking> {
@private
void *_priv;
}
- (void)wait;
- (BOOL)waitUntilDate:(NSDate *)limit;
- (void)signal;
- (void)broadcast;
遵循NSLocking协议,使用的时候同样是lock,unlock加解锁,wait是傻等,waitUntilDate:方法是等一会,都会阻塞掉线程,signal是唤起一个在等待的线程,broadcast是广播全部唤起。
NSCondition *lock = [[NSCondition alloc] init];
//Son 线程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lock];
while (No Money) {
[lock wait];
}
NSLog(@"The money has been used up.");
[lock unlock];
});
//Father线程
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lock];
NSLog(@"Work hard to make money.");
[lock signal];
[lock unlock];
});
2.NSConditionLock:
定义:
@interface NSConditionLock : NSObject <NSLocking> {
@private
void *_priv;
}
- (instancetype)initWithCondition:(NSInteger)condition NS_DESIGNATED_INITIALIZER;
@property (readonly) NSInteger condition;
- (void)lockWhenCondition:(NSInteger)condition;
- (BOOL)tryLock;
- (BOOL)tryLockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;
- (BOOL)lockBeforeDate:(NSDate *)limit;
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;
很简单,方法很清晰,基本同上。
分布式锁
NSDistributedLock
NSDistributedLock是MAC开发中的跨进程的分布式锁,底层是用文件系统实现的互斥锁。NSDistributedLock没有实现NSLocking协议,所以没有lock方法,取而代之的是非阻塞的tryLock方法。
NSDistributedLock*lock = [[NSDistributedLockalloc] initWithPath:@"/Users/mac/Desktop/lock.lock"];while(![lock tryLock]) { sleep(1); }//do something[lock unlock];
当执行到do something时程序退出,程序再次启动之后tryLock就再也不能成功了,陷入死锁状态.其他应用也不能访问受保护的共享资源。在这种情况下,你可以使用breadLock方法来打破现存的锁以便你可以获取它。但是通常应该避免打破锁,除非你确定拥有进程已经死亡并不可能再释放该锁
信号量
dispatch_semaphore:
// 初始化dispatch_semaphore_tsemaphore_t= dispatch_semaphore_create(1);// 加锁dispatch_semaphore_wait(semaphore_t,DISPATCH_TIME_FOREVER);// 解锁dispatch_semaphore_signal(semaphore_t);/* 注: dispatch_semaphore 其他两个功能 1.还可以起到阻塞线程的作用. 2.可以实现定时器功能,这里不做过多介绍.