OS中atomic的实现解析
OS中atomic的实现解析
atomic原子性与non-atomic非原子性
iOS中有两个属性non-atomic和atomic,前者是非原子性的(线程不安全),后者是原子性的(线程安全),一般情况下不会去重写它们,但某些时候确实有重写的需求。
那些int、float之类的类型,你重写想出错都很难。但是强引用类型(retain)就需要注意了。
简单的说一下非原子性的nonatomic实现,方式如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
- (void)setCurrentImage:(UIImage *)currentImage{ if (_currentImage != currentImage) { [_currentImage release]; _currentImage = [currentImage retain]; // do something }}- (UIImage *)currentImage{ return _currentImage;} |
atomic实现:
关于atomic的实现最开始的方式如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
- (void)setCurrentImage:(UIImage *)currentImage{ @synchronized(self) { if (_currentImage != currentImage) { [_currentImage release]; _currentImage = [currentImage retain]; // do something } }}- (UIImage *)currentImage{ @synchronized(self) { return _currentImage; }} |
具体讲就是retain的同步版本,本来以为没问题,但在用GCD重绘currentImage的过程中,有时候currentImage切换太频繁。在完成之前就把之前的currentImage释放了,程序仍然会崩溃。还需要在resize过程中增加retain和release操作,代码如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
- (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality { // For multithreading [self retain]; BOOL drawTransposed; CGAffineTransform transform = CGAffineTransformIdentity; // In iOS 5 the image is already correctly rotated. See Eran Sandler's // addition here: http://eran.sandler.co.il/2011/11/07/uiimage-in-ios-5-orientation-and-resize/ if([[[UIDevice currentDevice]systemVersion]floatValue] >= 5.0) { drawTransposed = NO; } else { switch(self.imageOrientation) { case UIImageOrientationLeft: case UIImageOrientationLeftMirrored: case UIImageOrientationRight: case UIImageOrientationRightMirrored: drawTransposed = YES; break; default: drawTransposed = NO; } transform = [self transformForOrientation:newSize]; } transform = [self transformForOrientation:newSize]; UIImage *image = [self resizedImage:newSize transform:transform drawTransposed:drawTransposed interpolationQuality:quality]; [self release]; return image;} |
原始版本的resize函数如下:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
- (UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality { BOOL drawTransposed; CGAffineTransform transform = CGAffineTransformIdentity; // In iOS 5 the image is already correctly rotated. See Eran Sandler's // addition here: http://eran.sandler.co.il/2011/11/07/uiimage-in-ios-5-orientation-and-resize/ if([[[UIDevice currentDevice]systemVersion]floatValue] >= 5.0) { drawTransposed = NO; } else { switch(self.imageOrientation) { case UIImageOrientationLeft: case UIImageOrientationLeftMirrored: case UIImageOrientationRight: case UIImageOrientationRightMirrored: drawTransposed = YES; break; default: drawTransposed = NO; } transform = [self transformForOrientation:newSize]; } transform = [self transformForOrientation:newSize]; return [self resizedImage:newSize transform:transform drawTransposed:drawTransposed interpolationQuality:quality];} |
但是之前在没有重写getter之前,用atomic的getter程序不会崩溃。于是我就想现在的getter和atomic自己实现的getter肯定有区别。
最后,答案出现:在getter的return之前retain,再autorelease一次就可以了。getter函数就变成了这样:
|
1
2
3
4
5
6
7
|
- (UIImage *)currentImage{ @synchronized(self) { UIImage *image = [_currentImage retain]; return [image autorelease]; }} |
这样可以确保currentImage在调用过程中不会因为currentImage被释放或者改变,使它的retainCount次数变为0,再在调用时让程序直接崩溃。
Runtime方法
在Memory and thread-safe custom property methods这篇文章中还提到了一种Objective-C的runtime解决方案。
Objective-C的runtime中实现了以下函数:
|
1
2
3
|
id <strong>objc_getProperty</strong>(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic);void <strong>objc_setProperty</strong>(id self, SEL _cmd, ptrdiff_t offset, id newValue, BOOL atomic, BOOL shouldCopy);void <strong>objc_copyStruct</strong>(void *dest, const void *src, ptrdiff_t size, BOOL atomic, BOOL hasStrong); |
这几个函数被实现了,但没有被声名。如果要使用他们,必须自己声名。它们比用@synchronized实现的要快。因为它的实现方式与一般情况不同,静态变量只在接收并发时才会锁住。
声名方式:
|
1
2
3
4
5
6
7
8
|
#define <strong>AtomicRetainedSetToFrom</strong>(dest, source) \ objc_setProperty(self, _cmd, (ptrdiff_t)(&dest) - (ptrdiff_t)(self), source, YES, NO)#define <strong>AtomicCopiedSetToFrom</strong>(dest, source) \ objc_setProperty(self, _cmd, (ptrdiff_t)(&dest) - (ptrdiff_t)(self), source, YES, YES)#define <strong>AtomicAutoreleasedGet</strong>(source) \ objc_getProperty(self, _cmd, (ptrdiff_t)(&source) - (ptrdiff_t)(self), YES)#define <strong>AtomicStructToFrom</strong>(dest, source) \ objc_copyStruct(&dest, &source, sizeof(__typeof__(source)), YES, NO) |
用这些宏定义,上面something的copy getter和setter方法将变成这样:
|
1
2
3
4
5
6
7
8
|
- (NSString *)someString{ return AtomicAutoreleasedGet(someString);}- (void)setSomeString:(NSString *)aString{ AtomicCopiedSetToFrom(someString, aString);} |
someRect存取方法将变成这样:
|
1
2
3
4
5
6
7
8
9
10
|
- (NSRect)someRect{ NSRect result; AtomicStructToFrom(result, someRect); return result;}- (void)setSomeRect:(NSRect)aRect{ AtomicStructToFrom(someRect, aRect);} |
OS中atomic的实现解析的更多相关文章
- .NET Core中的认证管理解析
.NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...
- 让 ASP.NET vNext 在 Mac OS 中飞呀飞。。。
写在前面 阅读目录: 娓娓道来 Install ASP.NET vNext Command Line Tools 安装 Homebrew 使用 Homebrew,安装 KVM Install Subl ...
- AngularJS中的指令全面解析(转载)
说到AngularJS,我们首先想到的大概也就是双向数据绑定和指令系统了,这两者也是AngularJS中最为吸引人的地方.双向数据绑定呢,感觉没什么好说的,那么今天我们就来简单的讨论下AngularJ ...
- Java中的static关键字解析
Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键 ...
- Java中的static关键字解析 转载
原文链接:http://www.cnblogs.com/dolphin0520/p/3799052.html Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到 ...
- [JavaScript] JS中对Base64的解析
JS中对Base64的解析 <script type="text/javascript"> /** * UTF16和UTF8转换对照表 * U+00000000 – U ...
- Oracle中Clob类型处理解析:ORA-01461:仅可以插入LONG列的LONG值赋值
感谢原作者:破剑冰-Oracle中Clob类型处理解析 上一篇分析:ORA-01461: 仅能绑定要插入 LONG 列的 LONG 值 最近为Clob字段在插入数据时发现当字符的字节数(一个半角字符一 ...
- Java中的static关键字解析(转自海子)__为什么main方法必须是static的,因为程序在执行main方法的时候没有创建任何对象,因此只有通过类名来访问。
Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到的比较难以理解的一个关键字,也是各大公司的面试官喜欢在面试时问到的知识点之一.下面就先讲述一下static关键 ...
- 【Chromium中文文档】Chrom{e,ium}{,OS}中的硬件视频加速
Chrom{e,ium}{,OS}中的硬件视频加速 转载请注明出处:https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh//General_ ...
随机推荐
- Jmeter发送Java请求
1.创建一个Java工程 2.把Jmeter的lib\ext目录下的ApacheJMeter_java.jar.ApacheJMeter_core.jar文件添加进该项目的Build Path 3.创 ...
- UML大战需求分析——阅读笔记03
读<UML大战需求分析>有感03 状态机图和活动图在样子比较相似,但状态机图是用来为对象的状态及造成状态改变的事件建模.我们大二学习UML统一建模语言状态机图模块时了解到,UML的状态机图 ...
- Mac OS X上搭建伪分布式CDH版本Hadoop开发环境
最近在研究数据挖掘相关的东西,在本地 Mac 环境搭建了一套伪分布式的 hadoop 开发环境,采用CDH发行版本,省时省心. 参考来源 How-to: Install CDH on Mac OSX ...
- Golang 语法学习笔记
Golang 语法学习笔记 包.变量和函数. 包 每个 Go 程序都是由包组成的. 程序运行的入口是包 main. 包名与导入路径的最后一个目录一致."math/rand" 包由 ...
- CURL 模拟http提交
1:CURL模拟get提交 private function httpGet($url) { $curl = curl_init(); curl_setopt($curl, CURLOPT_RETUR ...
- 阿里开源消息中间件RocketMQ的前世今生-转自阿里中间件
昨天,我们将分布式消息中间件RocketMQ捐赠给了开源软件基金会Apache. 孵化成功后,RocketMQ或将成为国内首个互联网中间件在Apache上的顶级项目. 消息一出,本以为群众的反应是这样 ...
- SPOJ - PLSQUARE Palin Squar(hash+回文串)
题意:给你一个n*n (n<=200)的字符串矩阵,问你每行每列都是回文串的最大的m*m的矩阵是多少 题解:首先答案不满足单调性,即m成立而m-1与m+1都却不一定成立,所以必须枚举答案确定现在 ...
- sip协议音视频性能测试
http://www.cnblogs.com/wxiaoqin/p/3629926.html https://www.myvoipapp.com/cn/docs/faq/performance_tes ...
- Nginx - Linux下按天分割日志
待完善. 可参考:https://www.iteblog.com/archives/1244
- ubuntu14.04 安装 搜狗输入法
1.安装或者更新fcitx libssh2-1:sudo apt-get install fcitx libssh2-1; 2.搜索是否安装成功: dpkg -l | grep fcitx ; dp ...