一.线程同步
- 线程同步,字面意思好像是多个线程一起工作.
其实不然,这里的同是协同,互相配合的意思,也就是多个线程互相配合,按照预定顺序依次执行的意思. - 我们平时所用的各种锁(比如NSLock,OSSpinLock,NSRecursiveLock)也是线程同步的一部分
- tips:系统提供的atomic保证了属性的原子性,但是仅仅只是在get方法和set方法的时候使用自旋锁,并不是线程安全.
比如多个线程对可变数组的增删
static inline void reallySetProperty(id self, SEL _cmd, id newValue, ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) {
if (!atomic) {
oldValue = *slot;
*slot = newValue;
} else {
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();
oldValue = *slot;
*slot = newValue;
slotlock.unlock();
}
}
二.同步&异步&并发&串行
- 同步:在当前线程执行任务,不具备开辟新线程的能力(dispatch_sync)同步会阻塞当前线程
- 异步:在新的线程执行任务,具备开辟新线程的能力(dispatch_async)
- 并发:多个任务同时执行(dispatch_globalQueue), 单个cpu单位时间内执行多个程序,时间片轮转
- 并行:多个任务同时执行(dispatch_globalQueue), 多个cpu同时执行多个程序
- 串行:one by one, 一个任务执行完毕才能执行下一个任务(dispatch_oncurrentQueue)
- 产生死锁的条件: sync + 串行队列
- sync: 阻塞当前线程 async: 不阻塞当前线程
三.iOS中的线程同步
- 可以通过信号量来实现gcd的控制线程数量
1.NSOperation线程依赖
[operation2 addDependency:operation1]; //任务二依赖任务一
[operation3 addDependency:operation2]; //任务三依赖任务二
相对于NSOperation而言,GCD没有这么简单的线程依赖的方法,它是通过信号量的方法来实现的.下面简单粗暴的贴代码
2.GCD线程依赖
1.关于信号量
信号量简介
2.代码
/**
信号量用法,类似于NSOperation的线程依赖
让thread1,thread2,thread3顺序执行
DISPATCH_QUEUE_PRIORITY_HIGH --> 大概的优先级,实际上没有那么准
@return 空
*/
- (void)GCDSemaphoreDemo //semaphore['s?m?f?r]信号量
{
NSMutableArray *arr = [NSMutableArray array];
dispatch_semaphore_t semaphore0 = dispatch_semaphore_create(0);//创建信号量,它的值为0
dispatch_semaphore_t semaphore1 = dispatch_semaphore_create(0);//让3个线程顺序执行,所以为0
//thread3
//希望它是最后执行的,让它依赖thread2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//DISPATCH_TIME_FOREVER表示一直等着,直到semaphore为0执行.如果写15的话,就代表我只等15纳秒,15纳秒后,不管信号量是否为0,我都执行下面的代码.
dispatch_semaphore_wait(semaphore1, DISPATCH_TIME_FOREVER);//阻塞当前线程一直到semaphore1为0
NSLog(@"最弱的,最后执行的--- > %@",arr);
});
//thread2
//等待thread1执行完毕后,执行thread2.(thread2依赖thread1)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//wait信号量-1(少一个可用资源)
dispatch_wait(semaphore0, DISPATCH_TIME_FOREVER);
NSLog(@"依赖别人的资源 --> %@",arr);
dispatch_semaphore_signal(semaphore1);
});
//thread1
//这里有arr的赋值操作,需要最先执行,否则其他地方打印都为空
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
for(int i = 0; i < 3; i ++)
{
[arr addObject:[NSNumber numberWithInt:i]];
}
NSLog(@"被依赖的资源 ---> %@",arr);
//signal相当于信号量+1(多一个可用资源)
dispatch_semaphore_signal(semaphore0);
});
}
3.使用dispatch_barrier_async也可以控制线程顺序(多读单写)
1.dispatch_barrier_async():dispatch_barrier_sync():使用此方法创建的任务首先会查看队列中有没有别的任务要执行,如果有,则会等待已有任务执行完毕再执行;同时在此方法后添加的任务必须等待此方法中任务执行后才能执行。(利用这个方法可以控制执行顺序,例如前面先加载最后一张图片的需求就可以先使用这个方法将最后一张图片加载的操作添加到队列,然后调用dispatch_async()添加其他图片加载任务)
2.说明dispatch_barrier_async的顺序执行还是依赖queue的类型啊,必需要queue的类型为dispatch_queue_create创建的,而且attr参数值必需是DISPATCH_QUEUE_CONCURRENT类型,前面两个非dispatch_barrier_async的类型的执行是依赖其本身的执行时间的,如果attr如果是DISPATCH_QUEUE_SERIAL时,那就完全是符合Serial queue的FIFO特征了。
4. 多读单写
- 多读单写, 需要满足以下3个条件
允许多条线程读取
只允许一条线程写入
同一时间,只允许读和写 - 可以使用dispatch_barrier_async或者
pthread_rwlock
读写锁
四.子线程中的perform方法
主线程中,以下两种方式都会执行,没有区别
[self performSelector:@selector(s) withObject:nil];
[self performSelector:@selector(s) withObject:nil afterDelay:.0];//主线程自带runloop
如果开启了子线程,一个执行,一个不执行
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//会执行,本质上是执行msgSend方法
[self performSelector:@selector(s) withObject:nil];
//不会执行,本质上是依赖runloop的timer, 而该子线程没有runloop,所以不会执行
[self performSelector:@selector(s) withObject:nil afterDelay:.0];
});
五.iOS中的线程同步方案
- OSSpinLock 自旋锁(不建议使用)
1.1 自旋锁,等待锁的线程会处于忙等(busy-wait),一直占用cpu资源(while循环)
1.2 不安全,可能会出现优先级反转的问题(系统给低优先级线程先加锁,导致高优先级线程忙等,但高优先级线程占用了大量cpu,导致没有资源分配给低优先级,系统卡死) - os_unfair_lock(效率最高)
2.1 os_unfair_lock支持iOS10.0以上系统,用来替代OSSpinLock
2.2 等待os_unfair_lock的线程会处于休眠状态,而非忙等 - pthread_mutex 互斥锁
3.1 mutex互斥锁,等待锁的线程会处于休眠状态 对应第6条
3.2 recursive递归锁,允许同一个线程重复加锁,用来处理嵌套函数(防止死锁) 对应7
3.3 conditon条件锁 对应8 - dispatch_semaphore
- dispatch_queue (DISPATCH_QUEUE_SERIAL)
- NSLock
- NSRecursiveLock
- NSCondition
- NSConditionLock
对NSCondition的封装 - Synchronized
对pthread——recursive的封装,根据传进来的对象生成一把递归锁
不推荐,性能较差
五.参考
http://blog.csdn.net/u014205965/article/details/45915135
http://08643.cn/p/a4ea43179870