ObjC 多線程簡析(二)- os_unfair_lock的類型和自旋鎖與互斥鎖的比較

在iOS10以後apple廢棄了OSSpinLock自旋鎖,使用os_unfair_lock來替代。api

OSSpinLock的api註釋中明確指出這是一個自旋鎖,那麼它的替代方案是一把什麼類型的鎖呢?xcode

OSSpinLock

咱們知道自旋鎖加鎖的時候,等待鎖的線程處於忙等狀態,而且佔用着CPU的資源。而互斥鎖加鎖的時候,等待鎖的線程處於休眠狀態,不會佔用CPU的資源。sass

那麼咱們探就加鎖狀態下的等待鎖的線程的狀態就能夠得出os_unfair_lock這把鎖的類型。多線程

探究os_unfair_lock的類型

依然使用上一篇中提到的賣票的案例。,分別使用OSSpinLockos_unfair_lock加鎖,當第二條線程執行到加鎖代碼的時候,是處於等待鎖的狀態,這個時候咱們經過彙編代碼窺探等待鎖的線程的狀態,得出其是自旋鎖仍是互斥鎖。app

#import "ViewController.h"

@interface ViewController ()
@property (nonatomic, assign) int ticketCount;
@end

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // 初始化鎖
    // ...
    [self ticket];
}

- (void)saleTicket {
    // 加鎖
    // ...
    int oldTicketCount = _ticketCount;
    sleep(1); //讓線程睡眠1秒 更能體現多線程的隱患
    oldTicketCount --;
    _ticketCount = oldTicketCount;
    NSLog(@"剩餘的票數%d",_ticketCount);
    // 解鎖
    // ...
}

- (void)ticket {
    self.ticketCount = 20;
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 5; i++) {
            [self saleTicket];
        }
    });
}
複製代碼

在Xcode中對加鎖代碼進行斷點,而後點擊任務欄Debug->Debug Worlflow->Always Show Disassembly。在xcode的lldb下使用si命令讓彙編代碼一步一步的執行,觀察等待鎖的線程狀態:async

彙編代碼

咱們發現線程進入了上述的狀態,這期是至關於一個while循環。這個循環等到自旋鎖解鎖以後進入下面的代碼繼續執行。這就是自旋鎖忙等的狀態。函數

下面咱們來看使用os_unfair_lock的狀況,使用它在代碼註釋的地方進行初始化,而且進行加鎖和解鎖,重複上述操做進行觀察。post

彙編

當彙編代碼執行到這一行的時候再也不繼續往下執行,斷點也失去了做用。這是由於syscall調用了系統內核的函數,使得線程進入休眠狀態,再也不佔用CPU資源。因此根據上面描述的自旋鎖和互斥鎖的區別os_unfair_lock屬於互斥鎖。ui

自旋鎖和互斥鎖的比較

當預計線程等待鎖的時間很短,或者加鎖的代碼(臨界區)常常被調用,但競爭狀況不多發生,再或者CPU資源不緊張,擁有多核處理器的時候使用自旋鎖比較合適。atom

而當預計線程等待鎖的時間較長,CPU是單核處理器,或者臨界區有IO操做,或者臨界區代碼複雜或者循環量大,臨界區競爭很是激烈的時候使用互斥鎖比較合適

總結

在iOS10以後apple已經再也不建議使用OSSpinLock自旋鎖了,它的替代方案是一個互斥鎖,因此通常狀況下咱們使用互斥鎖來解決線程同步的問題纔是比較合理的。

相關文章
相關標籤/搜索