NSLock
- (void)getIamgeName:(NSMutableArray *)imageNames{
NSString *imageName;
[lock lock];
if (imageNames.count>0) {
imageName = [imageNames lastObject];
[imageNames removeObject:imageName];
}
[lock unlock];
}
@synchronized代码块
- (void)getIamgeName:(int)index{
NSString *imageName;
@synchronized(self) {
if (imageNames.count>0) {
imageName = [imageNames lastObject];
[imageNames removeObject:imageName];
}
}
}
条件信号量dispatch_semaphore_t
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
semaphore = dispatch_semaphore_create(1);
/**
* 创建一个信号量为1的信号
*
*/
}
- (void)getIamgeName:(NSMutableArray *)imageNames{
NSString *imageName;
/**
* semaphore:等待信号
DISPATCH_TIME_FOREVER:等待时间
wait之后信号量-1,为0
*/
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
if (imageNames.count>0) {
imageName = [imageNames lastObject];
[imageNames removeObject:imageName];
}
/**
* 发送一个信号通知,这时候信号量+1,为1
*/
dispatch_semaphore_signal(semaphore);
}
条件锁NSCondition NSConditionLock(线程安全)(可用作线程同步)
- (void)getIamgeName:(NSMutableArray *)imageNames{
NSString *imageName;
[lock lock];
if (imageNames.count>0) {
imageName = [imageNames lastObject];
[imageNames removeObject:imageName];
}
[lock unlock];
}
递归锁NSRecursiveLock
递归使用
NSDistributedLock
互斥锁POSIX
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
pthread_mutex_init(&mutex, NULL);
/**
* 初始化
*
*/
}
- (void)getIamgeName:(NSMutableArray *)imageNames{
NSString *imageName;
/**
* 加锁
*/
pthread_mutex_lock(&mutex);
if (imageNames.count>0) {
imageName = [imageNames firstObject];
[imageNames removeObjectAtIndex:0];
}
/**
* 解锁
*/
pthread_mutex_unlock(&mutex);
}
自旋锁OSSpinLock(有bug)
新版 iOS 中,系统维护了 5 个不同的线程优先级/QoS: background,utility,default,user-initiated,user-interactive。高优先级线程始终会在低优先级线程前执行,一个线程不会受到比它更低优先级线程的干扰。这种线程调度算法会产生潜在的优先级反转问题,从而破坏了 spin lock。
具体来说,如果一个低优先级的线程获得锁并访问共享资源,这时一个高优先级的线程也尝试获得这个锁,它会处于 spin lock 的忙等状态从而占用大量 CPU。此时低优先级线程无法与高优先级线程争夺 CPU 时间,从而导致任务迟迟完不成、无法释放 lock。这并不只是理论上的问题,libobjc 已经遇到了很多次这个问题了,于是苹果的工程师停用了 OSSpinLock。
苹果工程师 Greg Parker 提到,对于这个问题,一种解决方案是用 truly unbounded backoff 算法,这能避免 livelock 问题,但如果系统负载高时,它仍有可能将高优先级的线程阻塞数十秒之久;另一种方案是使用 handoff lock 算法,这也是 libobjc 目前正在使用的。锁的持有者会把线程 ID 保存到锁内部,锁的等待者会临时贡献出它的优先级来避免优先级反转的问题。理论上这种模式会在比较复杂的多锁条件下产生问题,但实践上目前还一切都好。
OSSpinLock 自旋锁,性能最高的锁。原理很简单,就是一直 do while 忙等。它的缺点是当等待时会消耗大量 CPU 资源,所以它不适用于较长时间的任务。对于内存缓存的存取来说,它非常合适。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
spinlock = OS_SPINLOCK_INIT;
/**
* 初始化
*
*/
}
- (void)getIamgeName:(NSMutableArray *)imageNames{
NSString *imageName;
/**
* 加锁
*/
OSSpinLockLock(&spinlock);
if (imageNames.count>0) {
imageName = [imageNames firstObject];
[imageNames removeObjectAtIndex:0];
}
/**
* 解锁
*/
OSSpinLockUnlock(&spinlock);
}