1.线程死锁问题
1)
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"1111");
});
结果:会死锁,崩溃
原因:sync同步队列会阻塞当前线程(主线程),直到block里的任务完成。而执行任务的主线程已经被阻塞,不能在执行任务,所以就会死锁。
2)
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"1111");
});
NSLog(@"之后 - %@",[NSThread currentThread]);
NSLog(@"222");
});
结果:会阻塞当前线程,但是不会死锁崩溃;
原因:阻塞的是异步线程,执行任务的是主线程
3)
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"2-----%@",[NSThread currentThread]);
dispatch_sync(queue, ^{
NSLog(@"3-----%@",[NSThreadcurrentThread]);
});
});
结果:会造成死锁崩溃。
原因:sync会阻塞当前的线程,即
4)????????
dispatch_queue_tqueue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"11---%@",[NSThread currentThread]);
dispatch_queue_tqueue1 = dispatch_queue_create("test",DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue1, ^{
NSLog(@"22---%@",[NSThread currentThread]);
});
dispatch_sync(queue1, ^{
NSLog(@"33---%@",[NSThread currentThread]);
});
});
2.线程锁及其性能
来源:iOS中保证线程安全的几种方式与性能对比 -
iOS的线程安全与锁 - CocoaChina_让移动开发更简单
不再安全的 OSSpinLock | Garan no dou
深入理解 iOS 开发中的锁
@synchronized、NSLock、dispatch_semaphore、NSCondition、pthread_mutex、OSSpinLock
性能对比:
OSSpinLock: 46.15 ms
dispatch_semaphore: 56.50 ms
pthread_mutex: 178.28 ms
NSCondition: 193.38 ms
NSLock: 175.02 ms
pthread_mutex(recursive): 172.56 ms
NSRecursiveLock: 157.44 ms
NSConditionLock: 490.04 ms
@synchronized: 371.17 ms
1)OSSpinLock
自旋锁的实现原理比较简单,就是死循环。当a线程获得锁以后,b线程想要获取锁就需要等待a线程释放锁。在没有获得锁的期间,b线程会一直处于忙等的状态。如果a线程在临界区的执行时间过长,则b线程会消耗大量的cpu时间,不太划算。所以,自旋锁用在临界区执行时间比较短的环境性能会很高。
主要原因发生在低优先级线程拿到锁时,高优先级线程进入忙等(busy-wait)状态,消耗大量 CPU 时间,从而导致低优先级线程拿不到 CPU 时间,也就无法完成任务并释放锁。这种问题被称为优先级反转。
2)dispatch_semaphore
dispatch_semaphore实现的原理和自旋锁有点不一样。首先会先将信号量减一,并判断是否大于等于0,如果是,则返回0,并继续执行后续代码,否则,使线程进入睡眠状态,让出cpu时间。直到信号量大于0或者超时,则线程会被重新唤醒执行后续操作。
dispatch_semaphore_t lock = dispatch_semaphore_create(1); //创建信号量
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER); //降低信号量 等于0时需要等待
//需要执行的代码
dispatch_semaphore_signal(lock); //提升信号量
3)pthread_mutex
互斥锁的实现原理与信号量非常相似,不是使用忙等,而是阻塞线程并睡眠,需要进行上下文切换。
4)NSLock
NSLock 只是在内部封装了一个 pthread_mutex,属性为 PTHREAD_MUTEX_ERRORCHECK,它会损失一定性能换来错误提示。
5)@synchronized
这其实是一个 OC 层面的锁, 主要是通过牺牲性能换来语法上的简洁与可读。
我们知道 @synchronized 后面需要紧跟一个 OC 对象,它实际上是把这个对象当做锁来使用。这是通过一个哈希表来实现的,OC 在底层使用了一个互斥锁的数组(你可以理解为锁池),通过对对象去哈希值来得到对应的互斥锁。