1. 程式人生 > >iOS開發系列-線程同步技術

iOS開發系列-線程同步技術

%d syn rec 互斥鎖 body 排序 解決 nta 加鎖

概述

多線程的本質就是CPU輪流隨機分配給每條線程時間片資源執行任務,看起來多條線程同時執行任務。
技術分享圖片
多條線程同時訪問同一塊資源,比如操作同一個對象、統一變量、同一個文件,就會引發數據錯亂和數據安全的問題。

多線程引發問題實例

這裏我也借助網上兩個比較經典的案例,賣票和存取錢。

賣票案例

多個線程同時賣票,同一時間多個線層同時訪問票的總數,就會引發數據錯亂。
技術分享圖片

實例代碼

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

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.tickets = 30;
    [self saleTicketTest];
}

- (void)saleTicketWithName:(NSString *)name
{
   int currTicketCount = self.tickets;
    sleep(.2);
    currTicketCount--;
    self.tickets = currTicketCount;
    NSLog(@"當前%@賣了一張,票還剩:%d張", name ,self.tickets);
}

- (void)saleTicketTest
{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        for (int i=0; i<10; i++) {
            [self saleTicketWithName:@"A"];
        }
    });
    
    dispatch_async(queue, ^{
        for (int i=0; i<10; i++) {
            [self saleTicketWithName:@"B"];
        }
    });
    
    dispatch_async(queue, ^{
        for (int i=0; i<10; i++) {
            [self saleTicketWithName:@"C"];
        }
    });
}
@end

異常結果:
技術分享圖片

存錢取錢案例

技術分享圖片

實例代碼

#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, assign) int currMoney;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.currMoney = 1000;
    [self moneyTest];
}

- (void)moneyTest
{
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        for (int i=0; i<4; i++) {
            [self saveMoney];
        }
    });

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        for (int i=0; i<4; i++) {
            [self drawMoney];
        }
    });
}

// 存錢
- (void)saveMoney
{
    int money = self.currMoney;
    sleep(.3);
    money += 100;
    self.currMoney = money;
    NSLog(@"存了100,還剩%d元", self.currMoney);
    
}

// 取錢
- (void)drawMoney
{
    int money = self.currMoney;
    sleep(.3);
    money -= 50;
    self.currMoney = money;
    NSLog(@"取了50,還剩%d元", self.currMoney);
}

異常結果:
技術分享圖片

多線程安全隱患的解決方案

開發中解決多線程安全隱患的方案-使用線程同步技術。同步(協同步調,按預定的先後順序執行)
常見的線程同步技術就是加鎖

技術分享圖片

iOS中線程同步的方案根據性能優先級排序:

線程同步的方案 需要導入頭文件 類別 註意事項
os_unfair_lock <os/lock.h> 互斥鎖 iOS10才開始提供,用來替代OSSpinLock
OSSpinLock <libkern/OSAtomic.h> 自旋鎖 目前不在安全,可能會出現優先級反轉問題
dispatch_semaphore
pthread_mutex
dispatch_queue(DISPATCH_SENTINEL)
NSLock
oNSCondition <os/lock.h>
pthread_mutex(recuresive)
NSRecursiveLock
NSConditionLock
@synchronized

iOS開發系列-線程同步技術