OS中atomic的实现解析

转自:http://my.oschina.net/majiage/blog/267409 

摘要 atomic属性线程安全,会增加一定开销,但有些时候必须自定义atomic。这时候,我们就需要知道atomic的实现原理及方法了。这篇文章主要就是讲解自定义atomic的实现。

目录[-]

  • atomic原子性与non-atomic非原子性
  • atomic实现:
  • Runtime方法

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);
}

转载于:https://www.cnblogs.com/ruiying/p/4667586.html

OS中atomic的实现解析相关推荐

  1. OS中阻塞与挂起的区别sleep()的实现原理

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/xpy870663266/article ...

  2. Java并发编程包中atomic的实现原理

    转载自   Java并发编程包中atomic的实现原理 这是一篇来自粉丝的投稿,作者[林湾村龙猫]最近在阅读Java源码,这一篇是他关于并发包中atomic类的源码阅读的总结.Hollis做了一点点修 ...

  3. ios5中apple增加了解析JSON的api——NSJSONSerialization。

    ios5中apple增加了解析JSON的api--NSJSONSerialization.网上已经有人做过测试,NSJSONSerialization在效率上完胜SBJSON.TouchJSON.YA ...

  4. python中利用lxml模块解析xml文件报错XMLSyntaxError: Opening and ending tag mismatch

    今天在代码中第一次使用lxml解析xml文件时出错了, XMLSyntaxError: Opening and ending tag mismatch: keyEffectiveDate line 2 ...

  5. python中url是什么_怎么在Python中实现URL的解析

    怎么在Python中实现URL的解析 发布时间:2020-08-24 17:56:47

  6. AngularJS中的指令全面解析(必看)

    出处: http://www.jb51.net/article/84665.htm 说到AngularJS,我们首先想到的大概也就是双向数据绑定和指令系统了,这两者也是AngularJS中最为吸引人的 ...

  7. Java中的static关键字解析 转载

    原文链接:http://www.cnblogs.com/dolphin0520/p/3799052.html Java中的static关键字解析 static关键字是很多朋友在编写代码和阅读代码时碰到 ...

  8. spring中@Value的注解解析

    @Value的注解是通过AutowiredAnnotationBeanPostProcessor来处理的. 其处理时序为 其构造函数中添加了支持的注解类型 AutowireCandidateResol ...

  9. Vista OS 中添加网络中的非Vista OS共享的打印机

    需要首先在Vista OS中安装目标打印机的Vista驱动程序,其他步骤没什么特别.否则会提示"内存不足"这样的消息. 转载于:https://www.cnblogs.com/Fe ...

最新文章

  1. 一个分析“文件夹”选择框实现方法的过程
  2. php 代码规范 工具,PHP工具篇:PHPStorm IDE使用CodeSniffer代码规范化管理
  3. UIButton下面添加滑动的线
  4. 用C#和本地Windows API操纵系统菜单
  5. oleread.php,PHP的垃圾回收机制详解
  6. selenium 在centos中的配置
  7. javascript 之 面向对象【理解对象】
  8. 解决 Angular 官网下载的库 Schematics 在 windows 环境不支持 .. 的临时解决方案
  9. 同步方法 调用异步防范_Spring一个注解实现方法的异步调用,再也不用单开线程了...
  10. 拓端tecdat|R语言基于协方差的SEM结构方程模型中的拟合指数
  11. python爬取斗鱼弹幕_【Python3爬虫】斗鱼弹幕爬虫
  12. matlab遗传算法工具箱介绍和详细使用方法【matlab优化算法工具箱】
  13. C语言开定时器做呼吸灯程序,用定时器实现呼吸灯程序
  14. 自动交易软件的功能特点能满足哪些要求?
  15. 用帕累托图进行数据分析
  16. 第十六周助教心得体会
  17. 大话西游2玩家最多的服务器,大话西游2最火爆的服务器凌烟阁,玩家一次预约成功...
  18. 学生网页作业—山河旅行社网站(5页) HTML+CSS+JavaScript 学生DW网页 出行 旅途 游玩
  19. DenseBox: Unifying Landmark Localization with End to End Object Detection
  20. arduino uno r3单片机封装图_单片机控制的OLED简易电子表原型

热门文章

  1. android中解析后台返回的json字符串
  2. ORA-01940 无法删除当前已连接的用户之解决方案
  3. Linux最终将会领先于Windows、Mac OS!
  4. Python-条件控制及循环
  5. php 商务网站购物车联动地址
  6. 证券市场中银行的分类和作用
  7. MFC笔记2(控件位置调整)
  8. C#自定义ConfigSections节点操作
  9. Android—RecyclerView相关内容
  10. 安川机器人如何备份_YASKAWA机器人视觉局域网设置参考