OS中atomic的实现解析
OS中atomic的實現(xiàn)解析
轉(zhuǎn)自:http://my.oschina.net/majiage/blog/267409? 摘要?atomic屬性線程安全,會增加一定開銷,但有些時候必須自定義atomic。這時候,我們就需要知道atomic的實現(xiàn)原理及方法了。這篇文章主要就是講解自定義atomic的實現(xiàn)。?
目錄[-]
- atomic原子性與non-atomic非原子性
- atomic實現(xiàn):
- Runtime方法
atomic原子性與non-atomic非原子性
iOS中有兩個屬性non-atomic和atomic,前者是非原子性的(線程不安全),后者是原子性的(線程安全),一般情況下不會去重寫它們,但某些時候確實有重寫的需求。
那些int、float之類的類型,你重寫想出錯都很難。但是強引用類型(retain)就需要注意了。
簡單的說一下非原子性的nonatomic實現(xiàn),方式如下:
?| 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實現(xiàn):
關(guān)于atomic的實現(xiàn)最開始的方式如下:
?| 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函數(shù)如下:
?| 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程序不會崩潰。于是我就想現(xiàn)在的getter和atomic自己實現(xiàn)的getter肯定有區(qū)別。
最后,答案出現(xiàn):在getter的return之前retain,再autorelease一次就可以了。getter函數(shù)就變成了這樣:
?| 1 2 3 4 5 6 7 | -?(UIImage?*)currentImage { ????@synchronized(self)?{ ????????UIImage?*image?=?[_currentImage?retain]; ????????return?[image?autorelease]; ????} } |
?
這樣可以確保currentImage在調(diào)用過程中不會因為currentImage被釋放或者改變,使它的retainCount次數(shù)變?yōu)?,再在調(diào)用時讓程序直接崩潰。
?
Runtime方法
在Memory and thread-safe custom property methods這篇文章中還提到了一種Objective-C的runtime解決方案。
Objective-C的runtime中實現(xiàn)了以下函數(shù):
?| 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); |
?
?
這幾個函數(shù)被實現(xiàn)了,但沒有被聲名。如果要使用他們,必須自己聲名。它們比用@synchronized實現(xiàn)的要快。因為它的實現(xiàn)方式與一般情況不同,靜態(tài)變量只在接收并發(fā)時才會鎖住。
聲名方式:
?| 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); } |
轉(zhuǎn)載于:https://www.cnblogs.com/ruiying/p/4667586.html
總結(jié)
以上是生活随笔為你收集整理的OS中atomic的实现解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 舍得股票怎么成st了
- 下一篇: 慧辰资讯中签率