28.鎖

OSSpinLock

 NSString *phoneVersion  = [UIDevice currentDevice].systemVersion;
    if (phoneVersion.floatValue >= 10.0) {
        
        // 線程1
        
        __block os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
        
        dispatch_async(dispatch_get_main_queue(), ^{
           
            NSLog(@"準(zhǔn)備上鎖1");
            
            if (os_unfair_lock_trylock(&lock)) { // 嘗試加鎖 可以加鎖則立即加鎖并返回YES昆稿,反之返回NO
                
//                這里順便提一下trylock和lock使用場景:
//                當(dāng)前線程鎖失敗向族,也可以繼續(xù)其它任務(wù),用 trylock 合適
//                當(dāng)前線程只有鎖成功后腐宋,才會做一些有意義的工作喇完,那就 lock,沒必要輪詢 trylock
            }
            
            os_unfair_lock_lock(&lock);     // 加鎖
            
            os_unfair_lock_unlock(&lock);   // 解鎖
        });
        
    }else {
        
        // 線程1
        
        __block OSSpinLock lock = OS_SPINLOCK_INIT;
        
        dispatch_async(dispatch_get_main_queue(), ^{
            
            NSLog(@"準(zhǔn)備上鎖1");
            
            if (OSSpinLockTry(&lock)) { // 嘗試加鎖
                
//                這里順便提一下trylock和lock使用場景:
//                當(dāng)前線程鎖失敗蹬耘,也可以繼續(xù)其它任務(wù)钮科,用 trylock 合適
//                當(dāng)前線程只有鎖成功后,才會做一些有意義的工作婆赠,那就 lock绵脯,沒必要輪詢 trylock
            }
            
            OSSpinLockLock(&lock);      // 加鎖
            
            OSSpinLockUnlock(&lock);    // 解鎖
            
        });
    }
  • 如果一個低優(yōu)先級的線程獲得鎖并訪問共享資源佳励,這時一個高優(yōu)先級的線程也嘗試獲得這個鎖,它會處于 spin lock 的忙等狀態(tài)從而占用大量 CPU蛆挫。此時低優(yōu)先級線程無法與高優(yōu)先級線程爭奪CPU 時間赃承,從而導(dǎo)致任務(wù)遲遲完不成、無法釋放lock悴侵。這并不只是理論上的問題瞧剖,libobjc 已經(jīng)遇到了很多次這個問題了,于是蘋果的工程師停用了OSSpinLock可免。

dispatch_semaphore_t 信號量

dispatch_semaphore_t semaphore = dispatch_semaphore_create(10); // 傳入的值必須大于等于0抓于,若傳入0則阻塞線程并等待timeout,時間到后會執(zhí)行其后的語句
    
    dispatch_time_t overTime    = dispatch_time(DISPATCH_TIME_NOW, 3.0f * NSEC_PER_SEC);
    
    // 線程1
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        dispatch_semaphore_wait(semaphore, overTime); // signal值 +1
        
        NSLog(@"執(zhí)行耗時操作");
        
        dispatch_semaphore_signal(semaphore); // signal值 -1
        
    });

關(guān)于信號量浇借,我們可以用停車來比喻:

  • 停車場剩余4個車位捉撮,那么即使同時來了四輛車也能停的下。如果此時來了五輛車妇垢,那么就有一輛需要等待巾遭。
  • 信號量的值(signal)就相當(dāng)于剩余車位的數(shù)目,dispatch_semaphore_wait 函數(shù)就相當(dāng)于來了一輛車闯估,dispatch_semaphore_signal 就相當(dāng)于走了一輛車灼舍。停車位的剩余數(shù)目在初始化的時候就已經(jīng)指明了(dispatch_semaphore_create(long value)),調(diào)用一次 dispatch_semaphore_signal涨薪,剩余的車位就增加一個骑素;調(diào)用一次dispatch_semaphore_wait 剩余車位就減少一個;當(dāng)剩余車位為 0 時刚夺,再來車(即調(diào)用 dispatch_semaphore_wait)就只能等待献丑。有可能同時有幾輛車等待一個停車位。有些車主沒有耐心光督,給自己設(shè)定了一段等待時間阳距,這段時間內(nèi)等不到停車位就走了塔粒,如果等到了就開進(jìn)去停車结借。而有些車主就像把車停在這,所以就一直等下去卒茬。

pthread_mutex 互斥鎖 需要引入頭文件 <pthread.h>

 static pthread_mutex_t pLock;
    
    pthread_mutex_init(&pLock, NULL);
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        pthread_mutex_lock(&pLock); // 加鎖
        
        sleep(3); // 模擬耗時
        
        pthread_mutex_unlock(&pLock); // 解鎖
    });

pthread_mutex(recursive) 遞歸鎖

 static pthread_mutex_t pLock2;
    
    pthread_mutexattr_t attr;
    
    pthread_mutexattr_init(&attr); // 初始化attr并且給它賦予默認(rèn)
    
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); // 設(shè)置鎖類型船老,這邊是設(shè)置為遞歸鎖
    
    pthread_mutex_init(&pLock2, &attr);
    
    pthread_mutexattr_destroy(&attr); // 銷毀一個屬性對象,在重新進(jìn)行初始化之前該結(jié)構(gòu)不能重新使用
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        static void (^RecursiveBlock)(int);
        
        RecursiveBlock  = ^(int value) {
            
            pthread_mutex_lock(&pLock2);
            
            if (value > 0) {
                
                NSLog(@"value : %d",value);
                
                RecursiveBlock(value - 1);
            }
            
            pthread_mutex_unlock(&pLock2);
        };
        
        RecursiveBlock(5);
    });

NSLock 普通鎖

NSLock *lock    = [[NSLock alloc] init];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        [lock lock]; // 加鎖
        
        
        [lock unlock]; // 解鎖
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        // 嘗試加速
        BOOL x  = [lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:4]];
        
        if (x) {
            
            [lock unlock];
        }else {
            
            NSLog(@"失敗");
        }
    });

NSCondition

NSCondition *cLock  = [[NSCondition alloc] init];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        [cLock lock];  // 加鎖
        
        [cLock waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];  // 線程等待兩秒
        
        [cLock wait];   // 線程等待
        
        [cLock signal]; // 喚醒一個等待的線程
        
        [cLock broadcast]; // 喚醒所有等待的線程
        
        [cLock unlock]; // 解鎖
    });

NSRecursiveLock 遞歸鎖

 NSRecursiveLock *rLock   = [[NSRecursiveLock alloc] init];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        static void(^RecursiveBlock)(int);
        
        RecursiveBlock  = ^(int value){
        
            [rLock tryLock];
            
            if (value > 0) {
                
                RecursiveBlock(value - 1);
            }
            
            [rLock unlock];
        };
        
        RecursiveBlock(4);
    });

@synchronized 條件鎖

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        @synchronized (self) {
            
            sleep(2);
            
            NSLog(@"@synchronized線程");
        }
    });

NSConditionLock 條件鎖

NSConditionLock *cLock2  = [[NSConditionLock alloc] init];
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        if ([cLock2 tryLockWhenCondition:0]) {
            
            NSLog(@"NSConditionLock線程1");
            [cLock2 unlockWithCondition:1];
        } else {
            
            NSLog(@"失敗");
        }
        
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    
        if ([cLock2 tryLockWhenCondition:3]) {
            
//            [cLock2 lockWhenCondition:3];
            NSLog(@"NSConditionLock線程2");
            
            [cLock2 unlockWithCondition:2];
        } else {
            
            NSLog(@"失敗");
        }
    });
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        if ([cLock2 tryLockWhenCondition:1]) {
            
            NSLog(@"NSConditionLock線程3");
            [cLock2 unlockWithCondition:3];
        }
    });
  • 我們在初始化NSConditionLock 對象時圃酵,給了他的標(biāo)示為 0
  • 執(zhí)行 tryLockWhenCondition:時柳畔,我們傳入的條件標(biāo)示也是 0,所 以線程1 加鎖成功
  • 執(zhí)行 unlockWithCondition:時,這時候會把condition由 0 修改為 1
  • 因為condition 修改為了 1郭赐, 會先走到 線程3薪韩,然后 線程3 又將 condition 修改為 3
  • 最后 走了 線程2 的流程
  • 從上面的結(jié)果我們可以發(fā)現(xiàn),NSConditionLock 還可以實現(xiàn)任務(wù)之間的依賴。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末俘陷,一起剝皮案震驚了整個濱河市罗捎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拉盾,老刑警劉巖桨菜,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異捉偏,居然都是意外死亡倒得,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門夭禽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來霞掺,“玉大人,你說我怎么就攤上這事驻粟「浚” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵蜀撑,是天一觀的道長挤巡。 經(jīng)常有香客問我,道長酷麦,這世上最難降的妖魔是什么矿卑? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮沃饶,結(jié)果婚禮上母廷,老公的妹妹穿的比我還像新娘。我一直安慰自己糊肤,他們只是感情好琴昆,可當(dāng)我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著馆揉,像睡著了一般业舍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上升酣,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天舷暮,我揣著相機(jī)與錄音,去河邊找鬼噩茄。 笑死下面,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绩聘。 我是一名探鬼主播沥割,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼耗啦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了机杜?” 一聲冷哼從身側(cè)響起芹彬,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎叉庐,沒想到半個月后舒帮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡陡叠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年玩郊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枉阵。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡译红,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出兴溜,到底是詐尸還是另有隱情侦厚,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布拙徽,位于F島的核電站刨沦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏膘怕。R本人自食惡果不足惜想诅,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望岛心。 院中可真熱鬧来破,春花似錦、人聲如沸忘古。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽髓堪。三九已至送朱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間旦袋,已是汗流浹背骤菠。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工它改, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留疤孕,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓央拖,卻偏偏與公主長得像祭阀,于是被迫代替她去往敵國和親鹉戚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容