zoukankan      html  css  js  c++  java
  • OS中atomic的实现解析

    OS中atomic的实现解析

    转自:http://my.oschina.net/majiage/blog/267409 
     
    摘要 atomic属性线程安全,会增加一定开销,但有些时候必须自定义atomic。这时候,我们就需要知道atomic的实现原理及方法了。这篇文章主要就是讲解自定义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);
    }
  • 相关阅读:
    docker基于commit命令创建支持ssh服务的镜像
    CentOS 6.5 下Nginx服务的安装与配置
    CentOS 6.5 下搭建vsftp服务
    CentOS 6.5 下搭建FastDFS服务
    CentOS 6.5 下Nginx服务的安装与配置
    CentOS 6.5 下搭建NTP服务器
    CentOS6.5 下Haproxy服务的安装与配置
    CentOS 6.5 下HeartBeat的安装与配置
    CentOS 6.5 下keepalived服务的配置
    IDE vscode识别webpack中alias配置路径
  • 原文地址:https://www.cnblogs.com/ruiying/p/4667586.html
Copyright © 2011-2022 走看看