iOS开发线程安全问题
先来看一下代码:
- (void)viewDidLoad {
[super viewDidLoad];
self.testStr = @"String initial complete";
[self performSelector:@selector(changeStr) withObject:nil afterDelay:0.5];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, ), ^{
NSLog(@"before sleep %@",self.testStr);
sleep();
NSLog(@"after sleep %@",self.testStr);
});
}
- (void)changeStr{
self.testStr = @"String has changed";
}
执行结果:
-- ::40.525 线程安全测试[:] before sleep String initial complete
-- ::43.598 线程安全测试[:] after sleep String has changed
会发现在异步执行中如果testStr改变了,那么异步线程里的testStr也会改变这样就没法保证异步对资源独占操作
如果在异步block里创建一个str赋值如下代码:
- (void)viewDidLoad {
[super viewDidLoad];
self.testStr = @"String initial complete";
[self performSelector:@selector(changeStr) withObject:nil afterDelay:0.5];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, ), ^{
NSString *str = self.testStr;
NSLog(@"before sleep %@",str);
sleep();
NSLog(@"after sleep %@",str);
});
}
- (void)changeStr{
self.testStr = @"String has changed";
}
执行结果:
-- ::09.785 线程安全测试[:] before sleep String initial complete
-- ::12.786 线程安全测试[:] after sleep String initial complete
这样新的string就不会受到外部改变的影响,但是如果在这个赋值时刻self.asStr已变成野指针那么后面的操作还是会出错,虽然这样情况不是那么容易出现。
如何防止这种情况呢,可以看看下面的代码:
- (void)viewDidLoad {
[super viewDidLoad];
self.testStr = @"String initial complete";
[self performSelector:@selector(changeStr) withObject:nil afterDelay:0.5];
__weak __typeof(self.testStr) weakString = self.testStr;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, ), ^{
__strong __typeof(weakString) strongString = weakString;
if(strongString) {
NSLog(@"before sleep %@",strongString);
sleep();
NSLog(@"after sleep %@",strongString);
}
});
}
- (void)changeStr{
self.testStr = @"String has changed";
}
执行结果:
-- ::40.320 线程安全测试[:] before sleep String initial complete
-- ::43.388 线程安全测试[:] after sleep String initial complete
weakString会在self.asStr释放时置为nil,如果不是nil时,能够确保对象在block调用的完整周期里面被retain,如果被抢占对strongString的执行会继续并且会产生一样的值,如果strongString执行到时是nil,那么block不能正确执行前已经返回,这样就不会出现先前那样的问题。
还可以用锁来保证多个线程对一份资源在操作时不会被更改
#import "ViewController.h"
#include <pthread.h>
@interface ViewController ()
{
pthread_mutex_t _mutex;
}
@property (nonatomic, copy)NSString *testStr;
@end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad]; pthread_mutex_init(&_mutex, NULL);
self.testStr = @"String initial complete";
[self performSelector:@selector(changeStr) withObject:nil afterDelay:0.5];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, ), ^{
pthread_mutex_lock(&_mutex);
NSLog(@"before sleep %@",self.testStr);
sleep();
NSLog(@"after sleep %@",self.testStr);
pthread_mutex_unlock(&_mutex);
});
}
- (void)changeStr{ pthread_mutex_lock(&_mutex);
self.testStr = @"string has changed";
pthread_mutex_unlock(&_mutex);
}
- (void)dealloc
{
pthread_mutex_destroy(&_mutex);
}
@end
执行结果:
-- ::57.194 线程安全测试[:] before sleep String initial complete
-- ::00.269 线程安全测试[:] after sleep String initial complete
在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会在新系统中性能得到很大的提升,所以可以考虑这个方案。
iOS开发线程安全问题的更多相关文章
- iOS 开发线程 gcd
基础知识: 下午9:09 一.基础概念 1.什么是GCD 全称是Grand Central Dispath 纯C语言编写,提供非常多且强大的函数,是目前推荐的多线程开发方法,NSOperation ...
- iOS开发 - 线程与进程的认识与理解
进程: 进程是指在系统中正在运行的一个应用程序,比如同时打开微信和Xcode,系统会分别启动2个进程; 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内; 线程: 一个进程要想执行任务 ...
- iOS开发--线程通信
线程间的通信主要用于主线程与子线程的,也有用于子线程与子线程的 介绍下面几种通信方式 1.利用GCD方式(推荐) - (void)touchesBegan:(NSSet<UITouch *> ...
- iOS开发线程同步技术-锁
概览 1,什么是锁(临界区)? 2,常用的锁有哪些? 3,相关链接 什么是锁(临界区) 临界区:指的是一块对公共资源进行访问的代码,并非一种机制或是算法. 常用的锁有哪些? 互斥锁:是一种用于多线程编 ...
- iOS开发多线程篇—线程安全
iOS开发多线程篇—线程安全 一.多线程的安全隐患 资源共享 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块 ...
- iOS开发Swift篇(02) NSThread线程相关简单说明
iOS开发Swift篇(02) NSThread线程相关简单说明 一 说明 1)关于多线程部分的理论知识和OC实现,在之前的博文中已经写明,所以这里不再说明. 2)该文仅仅简单讲解NSThread在s ...
- 李洪强iOS开发Swift篇---12_NSThread线程相关简单说明
李洪强iOS开发Swift篇---12_NSThread线程相关简单说明 一 说明 1)关于多线程部分的理论知识和OC实现,在之前的博文中已经写明,所以这里不再说明. 2)该文仅仅简单讲解NSThre ...
- iOS开发多线程篇 03 —线程安全
iOS开发多线程篇—线程安全 一.多线程的安全隐患 资源共享 1块资源可能会被多个线程共享,也就是多个线程可能会访问同一块资源 比如多个线程访问同一个对象.同一个变量.同一个文件 当多个线程访问同一块 ...
- iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用
目的 本文主要是分享iOS多线程的相关内容,为了更系统的讲解,将分为以下7个方面来展开描述. 多线程的基本概念 线程的状态与生命周期 多线程的四种解决方案:pthread,NSThread,GCD,N ...
随机推荐
- [java大数据面试] 2018年4月百度面试经过+三面算法题:给定一个数组,求和为定值的所有组合.
给定一个数组,求和为定值的所有组合, 这道算法题在leetcode应该算是中等偏下难度, 对三到五年工作经验主要做业务开发的同学来说, 一般较难的也就是这种程度了. 简述经过: 不算hr面,总计四面, ...
- 计算器和Menu
MainActivity.java import android.app.Activity; import android.content.Intent; import android.os.Bund ...
- Android中如何使用xmlns
http://blog.csdn.net/lihenair/article/details/41009711 工作中时常需要自定义控件,除了按键,draw以外,还需要对控件属性进行一些初始化的操作,比 ...
- OPENSTACK在RHEL7安装;admin创建虚拟机模板供demo使用
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u010026901/article/details/30965601 首先RHEL7安装.导入镜像, ...
- jquery ajax 方法实例
每天学习一点点 编程PDF电子书.视频教程免费下载:http://www.shitanlife.com/code 直接上代码, ajax实例: $.ajax({ type : & ...
- ethereum/EIPs-161 State trie clearing
EIP 161: State trie clearing - makes it possible to remove a large number of empty accounts that wer ...
- ;,&,&&,shell,区别
command1&command2&command3 三个命令同时执行 command1;command2;command3 不管前面命令执行成功没有,后面的命令继续执 ...
- rc/rs的区别 -- 多层次分析
1.rs是rc的升级版本,rs一般会结合deployment 2.rc的pod如果要配置镜像等内容,要修改后删除原来的rc再创建 命令式,影响业务比较大 3.rs一般配合deployment,可以动 ...
- linux调度器源码分析 - 运行(四)
本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 之前的文章已经将调度器的数据结构.初始化.加入进程都进行了分析,这篇文章将主要说明调度器是如何在程序稳定运 ...
- Oracle 在函数或存储过程中执行sql查询字符串并将结果值赋值给变量
请看黄色部分 --区县指标 THEN TVALUE_SQL := 'SELECT TO_CHAR(' || CUR_ROW.MAIN_FIELD || ') FROM ' || CUR_ROW.END ...