最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入詳解Objective-C中的@Synchronized關(guān)鍵字

 更新時(shí)間:2023年03月30日 09:32:35   作者:iOS學(xué)習(xí)社區(qū)  
這篇文章主要為大家介紹了深入詳解Objective-C中的@Synchronized關(guān)鍵字,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

在多線程編程中,線程之間共享資源時(shí)容易出現(xiàn)數(shù)據(jù)競爭的問題,導(dǎo)致程序出現(xiàn)不可預(yù)期的結(jié)果。為了避免這種情況,我們需要采用一些同步機(jī)制來保證線程之間的安全協(xié)作。 @synchronized指令是Objective-C中一種常用的同步機(jī)制。

@synchronized指令是Objective-C中一種非常簡單方便的創(chuàng)建鎖的方式。相比于其他鎖,它的語法更加簡單,只需要使用任意一個(gè)Objective-C對象作為鎖標(biāo)記即可。

- (void)myMethod:(id)anObj {
    @synchronized(anObj) {
        // Everything between the braces is protected by the @synchronized directive.
    }
}

@synchronized指令中傳遞的對象是用于區(qū)分受保護(hù)代碼塊的唯一標(biāo)識符。如果在兩個(gè)不同的線程中執(zhí)行上述方法,分別為anObj參數(shù)傳遞不同的對象,那么每個(gè)線程都會獲取自己的鎖并繼續(xù)處理,而不會被另一個(gè)線程阻塞。但是,如果在這兩種情況下都傳遞相同的對象,則其中一個(gè)線程會首先獲取鎖,另一個(gè)線程則會被阻塞,直到第一個(gè)線程完成操作。

@Synchronized的底層實(shí)現(xiàn)

通過clang查看底層編譯代碼可知, @Synchronized是通過objc_sync_enter和objc_sync_exit函數(shù)來實(shí)現(xiàn)鎖的獲取和釋放的,源碼如下:

int objc_sync_enter(id obj)
{
    int result = OBJC_SYNC_SUCCESS;
    if (obj) {
        SyncData* data = id2data(obj, ACQUIRE);
        ASSERT(data);
        data->mutex.lock();
    } else {
        // @synchronized(nil) does nothing
        if (DebugNilSync) {
            _objc_inform("NIL SYNC DEBUG: @synchronized(nil); set a breakpoint on objc_sync_nil to debug");
        }
        objc_sync_nil();
    }
    return result;
}
int objc_sync_exit(id obj)
{
    int result = OBJC_SYNC_SUCCESS;
    if (obj) {
        SyncData* data = id2data(obj, RELEASE); 
        if (!data) {
            result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
        } else {
            bool okay = data->mutex.tryUnlock();
            if (!okay) {
                result = OBJC_SYNC_NOT_OWNING_THREAD_ERROR;
            }
        }
    } else {
        // @synchronized(nil) does nothing
    }
    return result;
}
  • 如果傳入的obj存在,則走加鎖流程;如果obj為nil,則什么也不做。
  • objc_sync_exit和objc_sync_enter是對應(yīng)的;objc_sync_exit方法就是解鎖,如果obj= nil則什么也不做;

通過觀察源碼可知,objc_sync_exit和objc_sync_enter里的關(guān)鍵是從obj轉(zhuǎn)換到SyncData,然后通過SyncData中的mutex來對臨界區(qū)上鎖。SyncData結(jié)構(gòu)體的定義如下:

typedef struct alignas(CacheLineSize) SyncData {
    struct SyncData* nextData;
    DisguisedPtr<objc_object> object;
    int32_t threadCount;  // number of THREADS using this block
    recursive_mutex_t mutex;
} SyncData;
  • mutex是遞歸鎖,這也是為什么可以在 @Synchronized里嵌套 @Synchronized的原因了。

從obj轉(zhuǎn)換到SyncData的具體實(shí)現(xiàn)如下:

這段代碼實(shí)現(xiàn)了一個(gè)鎖的緩存機(jī)制,目的是為了提高多線程訪問同一對象時(shí)的效率。當(dāng)多個(gè)線程同時(shí)訪問同一對象時(shí),每個(gè)線程需要獲取一個(gè)鎖,這會造成性能瓶頸。為了避免這個(gè)問題,緩存機(jī)制會將已經(jīng)獲取的鎖緩存起來,以供下次使用。其大致流程如下:

1、首先檢查是否啟用了快速緩存,如果啟用則在快速緩存中查找是否有與obj對應(yīng)的SyncData對象。

2、如果在快速緩存中找到了匹配的SyncData對象,則將syncLockCount加1,并返回結(jié)果。

3、如果沒有在快速緩存中找到匹配的SyncData對象,則繼續(xù)在線程緩存中查找是否有與obj對應(yīng)的鎖。

4、如果在線程緩存中找到了匹配的鎖,則將對應(yīng)鎖的計(jì)數(shù)加1,并將其返回結(jié)果。

5、如果沒有在線程緩存中找到匹配的鎖,則在全局的哈希表中查找是否有與obj對應(yīng)的SyncData對象。

6、如果在全局的哈希表中找到了匹配的SyncData對象,則會進(jìn)行多線程操作,將對應(yīng)鎖的計(jì)數(shù)加1,并返回結(jié)果。

7、如果沒有在全局的哈希表中找到匹配的SyncData對象,則創(chuàng)建新對象,并將新對象添加到上述的緩存中,以供下次使用。

badcase分析

#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) NSMutableArray *testArray;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.testArray = @[].mutableCopy;
    for (NSUInteger i = 0; i < 5000; i++) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            [self testThreadArray];
        });
    }
}
- (void)testThreadArray {
    @synchronized (self.testArray) {
        self.testArray = @[].mutableCopy;
    }
}
@end

運(yùn)行這段代碼,會出現(xiàn)如下crash:

考慮這個(gè)場景,有三個(gè)線程A、B、C同時(shí)訪問一個(gè)非原子屬性self.testArray,初始值為p0。線程A和線程B由于訪問的self.testArray的值一致,產(chǎn)生了競爭,線程A獲取了鎖并將self.testArray的值重新設(shè)置為p1,然后釋放了鎖。此時(shí)線程C訪問self.testArray,發(fā)現(xiàn)其值為p1,沒有競爭,準(zhǔn)備對其進(jìn)行賦值操作。然而,此時(shí)線程B由于之前的鎖已經(jīng)被釋放,進(jìn)入代碼塊,也準(zhǔn)備對self.testArray進(jìn)行賦值操作,這會導(dǎo)致兩個(gè)線程同時(shí)對非原子屬性self.testArray進(jìn)行賦值操作,從而產(chǎn)生crash。

以上就是深入詳解Objective-C中的@Synchronized關(guān)鍵字的詳細(xì)內(nèi)容,更多關(guān)于Objective-C @Synchronized關(guān)鍵字的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • iOS橫屏彈鍵盤的高度錯誤異常解決

    iOS橫屏彈鍵盤的高度錯誤異常解決

    這篇文章主要給大家介紹了關(guān)于iOS橫屏彈鍵盤的高度錯誤異常解決的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • iOS自定義字體設(shè)置和系統(tǒng)自帶的字體詳解

    iOS自定義字體設(shè)置和系統(tǒng)自帶的字體詳解

    這篇文章主要給大家介紹了關(guān)于iOS自定義字體設(shè)置和系統(tǒng)自帶的字體的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-01-01
  • iOS延遲執(zhí)行方法詳解

    iOS延遲執(zhí)行方法詳解

    這篇文章主要為大家詳細(xì)介紹了iOS延遲執(zhí)行方法,包括performSelector(NSObject)方法、NSTimer、GCD和sleep(NSThread)四種方法,需要的朋友可以參考下
    2016-11-11
  • iOS App中調(diào)用相冊中圖片及獲取最近的一張圖片的方法

    iOS App中調(diào)用相冊中圖片及獲取最近的一張圖片的方法

    這篇文章主要介紹了iOS App中調(diào)用相冊中圖片及獲取最近的一張圖片的方法,示例代碼為傳統(tǒng)的Objective-C語言,需要的朋友可以參考下
    2016-03-03
  • iOS 多線程總結(jié)之GCD的使用詳解

    iOS 多線程總結(jié)之GCD的使用詳解

    本篇文章主要介紹了iOS 多線程總結(jié)之GCD的使用詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • iOS內(nèi)存管理引用計(jì)數(shù)示例分析

    iOS內(nèi)存管理引用計(jì)數(shù)示例分析

    這篇文章主要為大家介紹了iOS內(nèi)存管理引用計(jì)數(shù)示例分析詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • IOS 開發(fā)之 NSMutableArray與NSArray 的區(qū)別

    IOS 開發(fā)之 NSMutableArray與NSArray 的區(qū)別

    這篇文章主要介紹了IOS 開發(fā)之 NSMutableArray與NSArray 的區(qū)別的相關(guān)資料,希望通過本文能掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-09-09
  • iOS錄屏和截屏監(jiān)聽的實(shí)現(xiàn)代碼

    iOS錄屏和截屏監(jiān)聽的實(shí)現(xiàn)代碼

    本篇文章主要介紹了iOS錄屏和截屏監(jiān)聽的實(shí)現(xiàn)代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • iOS應(yīng)用中使用AsyncSocket庫處理Socket通信的用法講解

    iOS應(yīng)用中使用AsyncSocket庫處理Socket通信的用法講解

    這篇文章主要介紹了iOS應(yīng)用中使用AsyncSocket庫處理Socket通信的用法講解,AsyncSocket同時(shí)支持TCP和UDP,文中展示了其建立斷開連接及發(fā)送接收消息的操作,very好用,需要的朋友可以參考下
    2016-05-05
  • iOS擼一個(gè)簡單路由Router的實(shí)現(xiàn)代碼

    iOS擼一個(gè)簡單路由Router的實(shí)現(xiàn)代碼

    這篇文章主要介紹了iOS擼一個(gè)簡單路由Router的實(shí)現(xiàn)代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-09-09

最新評論

山阴县| 乳源| 伽师县| 东丰县| 荥经县| 无锡市| 壤塘县| 彰化市| 达拉特旗| 丰顺县| 二手房| 临漳县| 上思县| 广汉市| 雅江县| 车致| 白城市| 马边| 湘阴县| 苏尼特左旗| 泰宁县| 岳普湖县| 奉化市| 简阳市| 台南县| 永定县| 陵水| 饶河县| 龙江县| 梧州市| 松潘县| 普兰县| 伽师县| 阿勒泰市| 西城区| 凤庆县| 麻栗坡县| 腾冲县| 田阳县| 湖南省| 高台县|