iOS开发--iOS多线程操作时一些要注意的安全问题
2016-11-14 11:02
393 查看
这次STMAssembleViewhttps://github.com/ming1016/STMAssembleView加入异步解析上线后发现一些线程安全方面的问题,现总结下。 先看看这段代码
执行结果
会发现在异步执行中如果asStr改变了,那么异步线程里的asStr也会改变这样就没法保证异步对资源独占操作。
如果在异步block里创建一个str赋值如下代码
执行结果
这样新的string就不会受到外部改变的影响,但是如果在这个赋值时刻self.asStr已变成野指针那么后面的操作还是会出错,虽然这样情况不是那么容易出现。
如何防止这种情况呢,可以看看下面的代码
执行结果
weakString会在self.asStr释放时置为nil,如果不是nil时,能够确保对象在block调用的完整周期里面被retain,如果被抢占对strongString的执行会继续并且会产生一样的值,如果strongString执行到时是nil,那么block不能正确执行前已经返回,这样就不会出现先前那样的问题。
还可以用锁来保证多个线程对一份资源在操作时不会被更改
执行结果
在RAC中使用的是OSSpinLock来保证线程安全的,不过几位苹果工程师在swift-dev邮件列表中讨论weak属性的线程安全问题的邮件里爆出自旋锁有bug,邮件地址:https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html。大概就是不同优先级线程调度算法会有优先级反转问题,比如低优先级获锁访问资源,高优先级尝试访问时会等待,这时低优先级又没法争过高优先级导致任务无法完成lock释放不了。也可以看看ReactiveCo社区的讨论https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2619
本来OSSpinLock是性能最高的锁,但是由于如果不在同一个优先级线程进行锁操作就不能保证安全,那么dispatch_semaphore和pthread_mutex这种仅次于自旋锁的可以作为替代方案。我注意到facebook的KVOController在2016年5月17日时的一个Commit里将所有OSSpinLock替换成了pthread_mutex,可参看这个commithttps://github.com/facebook/KVOController/commit/4f5c329b26f48b151eed82da085288763e2e1761。pthread_mutex会在新系统中性能得到很大的提升,所以可以考虑这个方案。
除非注明,均为Starming星光社原创,微信公共号 starming-weixin 发现更多,转载请注明本文地址:http://www.starming.com/index.php?v=index&view=102
- (void)viewDidLoad { [super viewDidLoad]; self.asStr = @"string is very first"; [self performSelector:@selector(doSomething) withObject:nil afterDelay:0.5]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NSLog(@"before sleep %@",self.asStr); sleep(3); NSLog(@"after sleep %@",self.asStr); }); } - (void)doSomething { self.asStr = @"string has changed"; }
执行结果
2016-08-31 20:58:43.927 HomePageTest[68018:535737] before sleep string is very first 2016-08-31 20:58:46.927 HomePageTest[68018:535737] after sleep string has changed
会发现在异步执行中如果asStr改变了,那么异步线程里的asStr也会改变这样就没法保证异步对资源独占操作。
如果在异步block里创建一个str赋值如下代码
- (void)viewDidLoad { [super viewDidLoad]; self.asStr = @"string is very first"; [self performSelector:@selector(doSomething) withObject:nil afterDelay:0.5]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NSString *str = self.asStr; NSLog(@"before sleep %@",str); sleep(3); NSLog(@"after sleep %@",str); }); } - (void)doSomething { self.asStr = @"string has changed"; }
执行结果
2016-08-31 20:59:50.094 HomePageTest[68075:537624] before sleep string is very first 2016-08-31 20:59:53.097 HomePageTest[68075:537624] after sleep string is very first
这样新的string就不会受到外部改变的影响,但是如果在这个赋值时刻self.asStr已变成野指针那么后面的操作还是会出错,虽然这样情况不是那么容易出现。
如何防止这种情况呢,可以看看下面的代码
- (void)viewDidLoad { [super viewDidLoad]; self.asStr = @"string is very first"; [self performSelector:@selector(doSomething) withObject:nil afterDelay:0.5]; __weak __typeof(self.asStr) weakString = self.asStr; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ __strong __typeof(weakString) strongString = weakString; if(strongString) { NSLog(@"before sleep %@",strongString); sleep(3); NSLog(@"after sleep %@",strongString); } }); } - (void)doSomething { self.asStr = @"string has changed"; }
执行结果
2016-08-31 21:00:24.457 HomePageTest[68131:538976] before sleep string is very first 2016-08-31 21:00:27.461 HomePageTest[68131:538976] after sleep string is very first
weakString会在self.asStr释放时置为nil,如果不是nil时,能够确保对象在block调用的完整周期里面被retain,如果被抢占对strongString的执行会继续并且会产生一样的值,如果strongString执行到时是nil,那么block不能正确执行前已经返回,这样就不会出现先前那样的问题。
还可以用锁来保证多个线程对一份资源在操作时不会被更改
@interface HomeViewController () { pthread_mutex_t _mutex; } @end @implementation HomeViewController - (void)viewDidLoad { [super viewDidLoad]; pthread_mutex_init(&_mutex, NULL); self.asStr = @"string is very first"; [self performSelector:@selector(doSomething) withObject:nil afterDelay:0.5]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ pthread_mutex_lock(&_mutex); self.asStr = @"string has changed in global queue"; NSLog(@"before sleep %@",self.asStr); sleep(3); NSLog(@"after sleep %@",self.asStr); pthread_mutex_unlock(&_mutex); }); } - (void)doSomething { pthread_mutex_lock(&_mutex); self.asStr = @"string has changed"; pthread_mutex_unlock(&_mutex); } - (void)dealloc { pthread_mutex_destroy(&_mutex); }
执行结果
2016-08-31 21:01:00.351 HomePageTest[68174:540038] before sleep string has changed in global queue 2016-08-31 21:01:03.354 HomePageTest[68174:540038] after sleep string has changed in global queue
在RAC中使用的是OSSpinLock来保证线程安全的,不过几位苹果工程师在swift-dev邮件列表中讨论weak属性的线程安全问题的邮件里爆出自旋锁有bug,邮件地址:https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html。大概就是不同优先级线程调度算法会有优先级反转问题,比如低优先级获锁访问资源,高优先级尝试访问时会等待,这时低优先级又没法争过高优先级导致任务无法完成lock释放不了。也可以看看ReactiveCo社区的讨论https://github.com/ReactiveCocoa/ReactiveCocoa/issues/2619
本来OSSpinLock是性能最高的锁,但是由于如果不在同一个优先级线程进行锁操作就不能保证安全,那么dispatch_semaphore和pthread_mutex这种仅次于自旋锁的可以作为替代方案。我注意到facebook的KVOController在2016年5月17日时的一个Commit里将所有OSSpinLock替换成了pthread_mutex,可参看这个commithttps://github.com/facebook/KVOController/commit/4f5c329b26f48b151eed82da085288763e2e1761。pthread_mutex会在新系统中性能得到很大的提升,所以可以考虑这个方案。
除非注明,均为Starming星光社原创,微信公共号 starming-weixin 发现更多,转载请注明本文地址:http://www.starming.com/index.php?v=index&view=102
相关文章推荐
- 总结iOS开发当中一些特别注意的问题
- [ios]总结iOS开发当中一些特别注意的问题 【转】
- 总结iOS开发当中一些特别注意的问题
- iOS10开发需要注意的一些问题(转)
- iOS开发Automatic Refernce Counting 下注意的一些问题
- iOS10开发需要注意的一些问题(转)
- [ios]总结iOS开发当中一些特别注意的问题 【转】
- 总结iOS开发当中一些特别注意的问题
- iOS 开发中的一些注意点(安全、当前语言、时间格式化)
- 总结iOS开发当中一些特别注意的问题
- Direct show 开发时注意的一些问题
- IOS开发的一些技巧和常见问题
- ActiveX控件开发的一些问题一,如何标记控件为安全
- IOS开发中一些尺寸问题
- java实际开发中泛型使用需要注意的一些问题
- ios SDK开发之关于CoreAnimation的一些注意点总结
- ios开发,一些注意项和常见错误
- 我在ios游戏开发中遇到的一些问题
- 开发BS系统中应该注意的一些问题
- 【IOS UI系列】UI开发中碰到的一些问题