底層原理:多線程

iOS中常見(jiàn)多線程方案

NSThreadGCDNSOperation 底層都是依賴(lài)于 pthread

GCD

GCD的常用函數(shù)
  • GCD中有兩個(gè)用來(lái)執(zhí)行任務(wù)的函數(shù)
  1. 用同步方式執(zhí)行任務(wù)(在當(dāng)前線程執(zhí)行任務(wù))
 dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
 // queue:隊(duì)列
 // block:任務(wù)
  1. 用異步的方式執(zhí)行任務(wù)
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
GCD的隊(duì)列
  • GCD的隊(duì)列可以分為兩大類(lèi)型
  1. 并發(fā)隊(duì)列(Concurrent Dispatch Queue)
  • 可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開(kāi)啟多個(gè)線程同時(shí)執(zhí)行任務(wù))
  • 并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
  1. 串行隊(duì)列
  • 讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù))
容易混淆的術(shù)語(yǔ)
  • 有4個(gè)術(shù)語(yǔ)比較容易混淆:同步、異步、并發(fā)、串行
    1. 同步和異步主要影響:能不能開(kāi)啟新的線程
    • 同步:在當(dāng)前線程中執(zhí)行任務(wù),不具備開(kāi)啟新線程的能力
    • 異步:在新的線程中執(zhí)行任務(wù),具備開(kāi)啟新線程的能力
    1. 并發(fā)和串行主要影響:任務(wù)的執(zhí)行方式
    • 并發(fā):多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行
    • 串行:一個(gè)任務(wù)執(zhí)行完畢后,再執(zhí)行下一個(gè)任務(wù)
    1. dispatch_async和dispatch_sync用來(lái)控制是否要開(kāi)啟新的線程,其只是具備開(kāi)啟新線程的能力。
    2. 主隊(duì)列也是一種特殊的串行隊(duì)列
各種隊(duì)列的執(zhí)行效果
并發(fā)隊(duì)列 串行隊(duì)列 主隊(duì)列
同步 沒(méi)有開(kāi)啟新線程 串行執(zhí)行任務(wù) 同左 同左
異步 有開(kāi)啟新線程 并發(fā)執(zhí)行任務(wù) 有開(kāi)啟新線程 串行執(zhí)行 同上
  • 總結(jié):只要是同步函數(shù)或者是主隊(duì)列就不會(huì)開(kāi)啟新線程,且為串行執(zhí)行任務(wù)

異步:

  • 不用等待當(dāng)前語(yǔ)句執(zhí)行完畢,就可以執(zhí)行下一條語(yǔ)句
  • 會(huì)開(kāi)啟新線程,異步是多線程的代名詞

同步:

  • 必須等待當(dāng)前語(yǔ)句執(zhí)行完畢,才會(huì)執(zhí)行下一條語(yǔ)句
  • 不會(huì)開(kāi)啟線程,在當(dāng)前線程執(zhí)行任務(wù)
截屏2025-08-15 16.21.59.png
隊(duì)列組

GCD的帶有 Create 的是不需要釋放的,帶有 CF 的是需要釋放的。

    //創(chuàng)建隊(duì)列組
    dispatch_group_t group = dispatch_group_create();
    //創(chuàng)建并發(fā)隊(duì)列
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    //添加異步任務(wù)
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i < 10; i++)
        {
            NSLog(@"任務(wù)1-%@",[NSThread currentThread]);
        }
    });
    
    dispatch_group_async(group, queue, ^{
        for (int i = 0; i < 10; i++)
        {
            NSLog(@"任務(wù)2-%@",[NSThread currentThread]);
        }
    });
    
    //等前面的任務(wù)執(zhí)行完后會(huì)自動(dòng)執(zhí)行這個(gè)任務(wù)
    dispatch_group_notify(group, queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            for (int i = 0; i < 10; i++)
            {
                NSLog(@"任務(wù)3-%@",[NSThread currentThread]);
            }
        });
    });
死鎖
  1. 以下代碼會(huì)出現(xiàn)死鎖
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    NSLog(@"任務(wù)1");
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"任務(wù)2");
    });
    NSLog(@"任務(wù)3");
}

出現(xiàn)死鎖的原因:dispatch_sync為同步執(zhí)行,同步的意思是立馬在當(dāng)前線程執(zhí)行任務(wù),執(zhí)行完畢才能繼續(xù)向下執(zhí)行,因此只有執(zhí)行完任務(wù)2才能執(zhí)行任務(wù)3,但是執(zhí)行任務(wù)2必須等上一個(gè)任務(wù)執(zhí)行完才能執(zhí)行2,也就是viewDidLoad執(zhí)行完才能執(zhí)行任務(wù)2,最終任務(wù)3在等任務(wù)2執(zhí)行完,任務(wù)2又在等viewDidLoad執(zhí)行完,而viewDidLoad需要等任務(wù)3執(zhí)行完,最終導(dǎo)致死鎖。

  1. 這種情況不會(huì)產(chǎn)生死鎖
- (void)test2
{
    NSLog(@"任務(wù)1");
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)2");
    });
    NSLog(@"任務(wù)3");
}

執(zhí)行的結(jié)果是先輸出任務(wù)1,再輸出任務(wù)3,最后任務(wù)2,不會(huì)死鎖的原因是dispatch_async不要求立馬在當(dāng)前線程同步執(zhí)行任務(wù),在執(zhí)行任務(wù)2的時(shí)候已經(jīng)出了test2的棧了。

  1. 這種情況也可以產(chǎn)生死鎖
- (void)test3
{
    NSLog(@"任務(wù)1");
    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{ //0
        NSLog(@"任務(wù)2");
        dispatch_sync(queue, ^{ //1
            NSLog(@"任務(wù)3");
        });
        
        NSLog(@"任務(wù)4");
    });
    
    NSLog(@"任務(wù)5");
}

產(chǎn)生死鎖的原因是:dispatch_sync要求立馬在當(dāng)前線程執(zhí)行block1,但要執(zhí)行block1有個(gè)前提條件是block0要從隊(duì)列中執(zhí)行完block1才能執(zhí)行,block0要執(zhí)行的話(huà)block1要執(zhí)行完它才能執(zhí)行任務(wù)4,因此產(chǎn)生死鎖。

  • 總結(jié):使用sync函數(shù)向當(dāng)前串行隊(duì)列中添加任務(wù),會(huì)卡住當(dāng)前的串行隊(duì)列(產(chǎn)生死鎖)
  1. 以下代碼的輸出結(jié)果
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        NSLog(@"1");

        [self performSelector:@selector(testLog) withObject:nil afterDelay:.0];
        NSLog(@"3");

//        [[NSRunLoop currentRunLoop]addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
//        [[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate: [NSDate distantFuture]];
    });
}

- (void )testLog
{
    NSLog(@"2");
}

輸出結(jié)果是:1和3,2是不會(huì)輸出的,因?yàn)橛?code>afterDelay的方法是跟runloop有關(guān)的,之所以會(huì)延遲本質(zhì)是向Runloop里面添加timer,其因?yàn)樵谧泳€程里runloop沒(méi)有啟動(dòng)故不會(huì)輸出,如果想要其正常輸出,需要將子線程的runloop啟動(dòng),即把注釋的代碼打開(kāi)即可。

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSLog(@"1");
    [self performSelector:@selector(testLog) withObject:nil afterDelay:.0];
    NSLog(@"3");
}

- (void )testLog
{
    NSLog(@"2");
}

這種情況下輸出結(jié)果是:1,3,2

performSelector里沒(méi)有 'afterDelay' 的只是被轉(zhuǎn)換成了 Objc_msgSend,而有 afterDelay 的是跟 RunLoop 相關(guān)的。

多線程的安全隱患
  • 可能會(huì)出現(xiàn)的隱患有:
  1. 資源共享
  • 一塊資源可能會(huì)被多個(gè)線程共享,也就是多個(gè)線程可能會(huì)訪問(wèn)同一塊資源
  • 比如多個(gè)線程訪問(wèn)同一個(gè)對(duì)象、同一個(gè)變量、同一個(gè)文件
  1. 當(dāng)多個(gè)線程訪問(wèn)同一塊資源時(shí),很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全問(wèn)題,如買(mǎi)票和存錢(qián)取錢(qián)問(wèn)題
多線程安全隱患的解決方案
  • 使用線程同步技術(shù)(同步,就是協(xié)同步調(diào),按預(yù)定的先后次序進(jìn)行)
  • 常見(jiàn)的線程同步技術(shù)是:加鎖,目的是保證當(dāng)前只有一條線程訪問(wèn),加鎖后記得要解鎖
線程阻塞

常見(jiàn)的線程阻塞有兩種:

  • 一種是sleep
  • 另外一種是while循環(huán),忙等,始終在等待直到鎖打開(kāi)。
iOS中的線程同步方案
  • OSSpinLock 自旋鎖
  • os_unfair_lock
  • pthread_mutex
  • dispatch_semaphore 信號(hào)量
  • dispatch_queue(DISPATCH_QUEUE_SERIAL)
  • NSLock
  • NSRecursiveLock
  • NSCondition
  • NSConditionLock
  • synchronized

1. OSSpinLock(已過(guò)期)

  • OSSpinLock叫做“自旋鎖”,等待鎖的線程會(huì)處于忙等(busy-wait)狀態(tài),一直占用著CPU資源
  • 目前已經(jīng)不再安全,可能會(huì)出現(xiàn)優(yōu)先級(jí)反轉(zhuǎn)問(wèn)題:如兩條線程同時(shí)訪問(wèn)saleTicket方法,如果優(yōu)先級(jí)低的線程先加了鎖,然后優(yōu)先級(jí)高的線程執(zhí)行到這個(gè)方法時(shí)發(fā)現(xiàn)有鎖,其會(huì)在此處忙等(while (是否有鎖) nil),但其由于優(yōu)先級(jí)高CPU給予了大量時(shí)間從而導(dǎo)致優(yōu)先級(jí)低的線程雖然進(jìn)入了方法內(nèi)部,但因優(yōu)先級(jí)低而導(dǎo)致無(wú)法執(zhí)行下一句代碼,導(dǎo)致這把鎖有可能放不開(kāi),造成類(lèi)似死鎖的現(xiàn)象。
  • 如果等待鎖的線程優(yōu)先級(jí)較高,它會(huì)一直占用著CPU資源,優(yōu)先級(jí)低的線程就無(wú)法釋放鎖
  • 需要導(dǎo)入頭文件#import <libkern/OSAtomic.h>

以賣(mài)票為例,完整的代碼是下面這樣子的

@interface ViewController ()

@property (nonatomic, assign) NSInteger ticketCount;
@property (nonatomic, assign) OSSpinLock lock; //C語(yǔ)言類(lèi)型的,故用assign

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    //初始化鎖
    OSSpinLock lock = OS_SPINLOCK_INIT;
    
    [self ticketTest];
}

- (void)ticketTest
{
    self.ticketCount = 15;
    dispatch_queue_t queue = dispatch_get_global_queue(0, DISPATCH_QUEUE_PRIORITY_DEFAULT);
    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];
        }
    });
}

- (void)saleTicket
{
    //加鎖
    OSSpinLockLock(&_lock);
    
    NSInteger count = self.ticketCount;
    sleep(.2);
    count--;
    self.ticketCount = count;
    NSLog(@"%@-------ticketCount = %ld",[NSThread currentThread],self.ticketCount);
    //解鎖
    OSSpinLockUnlock(&_lock);
}

@end
  • 注意事項(xiàng):在創(chuàng)建鎖時(shí)不能把創(chuàng)建鎖的操作放在saleTicket里,這樣的話(huà)會(huì)在這個(gè)方法每次執(zhí)行時(shí)創(chuàng)建一個(gè)鎖,各個(gè)線程之間的鎖不共用,因此不能實(shí)現(xiàn)同步的功能。
  • 計(jì)算機(jī)在調(diào)度進(jìn)程和線程時(shí)用的都是:時(shí)間片輪轉(zhuǎn)調(diào)度算法,即給每一條線程分配很短的時(shí)間,看越來(lái)像多條線程一塊執(zhí)行一梓,然后如果哪條線程的優(yōu)先級(jí)高的點(diǎn)就會(huì)多執(zhí)行一點(diǎn)時(shí)間。
  • OSSpinLock之前是性能最高的一種鎖,因?yàn)樗翘幱诿Φ?,忙等的好處是不?huì)讓線程睡眠,線程一旦睡著,再想把它喚醒,中間也是要耗性能的,也要花時(shí)間。

2. os_unfair_lock

  • os_unfair_lock用于取代不安全的OSSpinLock,從iOS10開(kāi)始才支持
  • 從底層調(diào)用看,等待os_unfair_lock鎖的線程會(huì)處于休眠狀態(tài),并非忙等
  • 需要導(dǎo)入頭文件#import <os/lock.h>

完整的代碼如下

@interface ViewController ()

@property (nonatomic, assign) NSInteger ticketCount;
@property (nonatomic, assign) os_unfair_lock lock;

@end

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    //初始化
    os_unfair_lock unfairLock = OS_UNFAIR_LOCK_INIT;
    self.lock = unfairLock;
}

- (void)saleTicket
{
    //嘗試加鎖 
    //os_unfair_lock_trylock(&_lock);
    //加鎖2
    os_unfair_lock_lock(&_lock);
    NSInteger count = self.ticketCount;
    sleep(.2);
    count--;
    self.ticketCount = count;
    NSLog(@"%@-------ticketCount = %ld",[NSThread currentThread],self.ticketCount);
    //如果忘記解鎖,專(zhuān)業(yè)術(shù)語(yǔ)叫死鎖
    os_unfair_lock_unlock(&_lock);
}

3. pthread_mutex

  • 帶P開(kāi)頭的一般都是跨平臺(tái)的
  • mutex叫做“互斥鎖”,等待鎖的線程會(huì)處于休眠狀態(tài),而“自旋鎖”剛好與這相反,是不休眠,一直旋轉(zhuǎn),一直在等和執(zhí)行代碼。

完整代碼如下:

#import <pthread.h>

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
   
    //初始化屬性
    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_DEFAULT);
    //初始化鎖
    pthread_mutex_t mutex;
    pthread_mutex_init(&_mutex,&attr);

    //銷(xiāo)毀屬性
    pthread_mutexattr_destroy(&attr);

    //嘗試加鎖
    pthread_mutex_trylock(&mutex);
    //加鎖
    pthread_mutex_lock(&_mutex);
    //減票操作
    //解鎖
    pthread_mutex_unlock(&_mutex);
}

- (void)dealloc
{
   //銷(xiāo)毀鎖
   pthread_mutex_destroy(&_mutex);
}

4.NSLock

  • NSLock 是對(duì) mutex 普通鎖的封裝,其實(shí)現(xiàn)了 NSLocking 協(xié)議
@interface NSLock : NSObject <NSLocking> 
- (BOOL)tryLock; //嘗試加鎖,如果不能加,返回NO
- (BOOL)lockBeforeDate:(NSDate *)limit;  //在這個(gè)時(shí)間點(diǎn)之前如果沒(méi)有等到這個(gè)鎖則休眠,如果到了這個(gè)時(shí)間點(diǎn)還沒(méi)有等到這個(gè)鎖,則加鎖失敗,返回NO
@end

使用方式

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLock *lock = [[NSLock alloc]init];
    [lock lock];
    [my test];
    [lock unLock];
}

5. NSRecursiveLock

  • NSRecursiveLock 也是對(duì) mutex 遞歸鎖的封裝,API跟 NSLock 基本一致

6. NSCondition

  • NSCondition 是對(duì) mutexcond 的封裝
@interface NSCondition : NSObject <NSLocking> 
- (void)wait;
- (BOOL)waitUntilDate:(NSDate *)limit;
- (void)signal;
- (void)broadcast;
@end

用法如下:

- (void)run
{
    [self.condition lock];
    //信號(hào),其他鎖也可以用 signal,用于喚醒等待的線程
    [self.condition signal];
    //等待,一旦設(shè)置為 wait 則其他線程可以加鎖
    [self.condition wait];
    [self.condition unLock];
}

7. NSConditionLock

  • NSConditionLock 是對(duì) NSCondition 的進(jìn)一步封裝,可以設(shè)置具體的條件值
@interface NSConditionLock : NSObject <NSLocking> 

@property (readonly) NSInteger condition;
- (void)lockWhenCondition:(NSInteger)condition;
- (BOOL)tryLock;
- (BOOL)tryLockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;
- (BOOL)lockBeforeDate:(NSDate *)limit;
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;

@end

8. dispatch_semaphore

  • semaphore 叫做信號(hào)量
  • 信號(hào)量的初始值,可以用來(lái)控制線程并發(fā)訪問(wèn)的最大數(shù)量
  • 信號(hào)量的初始值為1,代表同時(shí)只允許1條線程訪問(wèn)資源,保證線程同步
- (void)viewDidLoad {
    [super viewDidLoad];

    //信號(hào)量的初始值,可以用來(lái)控制線程并發(fā)訪問(wèn)的最大數(shù)量
    int value = 1;
    //初始化信號(hào)量
    dispatch_semaphore_t phore = dispatch_semaphore_create(value);
    //如果信號(hào)量的值<=0,當(dāng)前線程就會(huì)進(jìn)入休眠等待(直到信號(hào)量的值>0)
    //如果信號(hào)的值>0,就減1,然后往下執(zhí)行后面的代碼,DISPATCH_TIME_FOREVER表示一直等,直到有信號(hào)量的值大于1為止
    dispatch_semaphore_wait(phore, DISPATCH_TIME_FOREVER); // 這句代碼使value - 1
    //即最多有初始個(gè)值訪問(wèn)下面的代碼
    NSLog(@"%@",[NSThread currentThread]);
    //讓信號(hào)量的值加1
    dispatch_semaphore_signal(phore);
}

9. @synchronized

  • @synchronized 是對(duì) mutex 遞歸鎖的封裝
- (void)viewDidLoad {
    [super viewDidLoad];

    //拿self對(duì)象來(lái)做把鎖
    @synchronized (self)
    {
        NSLog(@"%@",[NSThread currentThread]);
    }
}

iOS 線程同步方案性能比較

性能從高到低排序

  • os_unfair_lock
  • OSSpinLock
  • dispatch_semaphore
  • pthread_mutex
  • dispatch_queue(DISPATCH_QUEUE_SERIAL)
  • NSLock
  • NSCondition
  • pthread_mutex(recursive)
  • NSRecursiveLock
  • NSConditionLock
  • @synchronized

其中遞歸鎖的效率最差,不推薦使用,推薦使用的是:dispatch_queue(DISPATCH_QUEUE_SERIAL)pthread_mutex

自旋鎖與互斥鎖對(duì)比

  • 什么情況使用自旋鎖比較劃算?

    • 預(yù)計(jì)線程等待鎖的時(shí)間很短
    • 加鎖的代碼(臨界區(qū))經(jīng)常被調(diào)用,但競(jìng)爭(zhēng)情況很少發(fā)生
    • CPU資源不緊張的情況(自旋鎖耗性能)
  • 什么情況使用互斥鎖比較劃算?

    • 預(yù)計(jì)線程等待鎖的時(shí)間較長(zhǎng)
    • 單核處理器
    • 臨界區(qū)有IO操作(IO操作占CPU資源)
    • 臨界區(qū)代碼復(fù)雜或者循環(huán)量大
    • 臨界區(qū)競(jìng)爭(zhēng)非常激烈

atomic

  • atomic 一般在Mac上用,在iOS上基本上不用,給屬性加上atomic屬性,可以保證屬性的 settergetter 都是原子性操作,相當(dāng)于在 gettersetter 內(nèi)部增加了線程同步的鎖,但僅限于 settergetter 內(nèi)部
  • 可以參考源碼 objc4objc-accesstors.mm
  • atomic 很耗性能,因此不常用,如果真的需要加鎖,在外面使用的時(shí)候加鎖。
iOS讀寫(xiě)安全方案
  • IO操作,即文件操作

    • 1.從文件中讀取內(nèi)容
    • 2.往文件中寫(xiě)入內(nèi)容,和讀取不能同時(shí)進(jìn)行

思考如何實(shí)現(xiàn)以下場(chǎng)景

  • 同一時(shí)間,只能有1個(gè)線程進(jìn)行寫(xiě)的操作
  • 同一時(shí)間,允許有多個(gè)線程進(jìn)行讀的操作
  • 同一時(shí)間,不允許既有寫(xiě)的操作,又有讀的操作

上面的場(chǎng)景就是典型的“多讀單寫(xiě)”,經(jīng)常用于文件等數(shù)據(jù)的讀寫(xiě)操作,iOS中的實(shí)現(xiàn)方案有:

  • pthread_rwlock::讀寫(xiě)鎖
  • dispatch_barrier_async:異步柵欄調(diào)用

pthread_rwlock用法如下:

    //初始化鎖
    pthread_rwlock_t lock;
    pthread_rwlock_init(&lock,NULL);
    //讀-加鎖
    pthread_rwlock_rdlock(&lock);
    //讀-嘗試加鎖
    pthread_rwlock_tryrdlock(&lock);
    //寫(xiě)-加鎖
    pthread_rwlock_wrlock(&lock);
    //寫(xiě)-嘗試加鎖
    pthread_rwlock_trywrlock(&lock);
    //解鎖
    pthread_rwlock_unlock(&lock);
    pthread_rwlock_destroy(&lock);

pthread_rwlock例子如下:

#import "SecondViewController.h"
#import <pthread.h>>
@interface SecondViewController ()
@property (nonatomic, assign) pthread_rwlock_t lock;
@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    pthread_rwlock_init(&_lock,NULL);
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    for (int i = 0; i < 10; i++)
    {
        dispatch_async(queue, ^{
            [self read];
        });
        
        dispatch_async(queue, ^{
            [self write];
        });
    }
}

- (void)read
{
    pthread_rwlock_rdlock(&_lock);
    NSLog(@"%s",__func__);
    pthread_rwlock_unlock(&_lock);
}

- (void)write
{
    pthread_rwlock_wrlock(&_lock);
    NSLog(@"%s",__func__);
    pthread_rwlock_wrlock(&_lock);
}
@end

dispatch_barrier_async用法

  • 這個(gè)函數(shù)傳入的并發(fā)隊(duì)列必須是自己通過(guò) dispatch_queue_create 創(chuàng)建的
  • 如果傳入的是一個(gè)串行或是一個(gè)全局的并發(fā)隊(duì)列,那這個(gè)函數(shù)便等同于 dispatch_async 函數(shù)的效果
#import "ThirdViewController.h"

@interface ThirdViewController ()
@property (nonatomic, strong) dispatch_queue_t queue;
@end

@implementation ThirdViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    self.queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 10; i++)
    {
        [self read];
        [self read];
        [self read];
        [self write];
    }
}

- (void)read
{
    dispatch_async(_queue, ^{
        NSLog(@"read");
    });
}

- (void)write
{
    dispatch_barrier_sync(_queue, ^{
        NSLog(@"write");
    });
}
@end

GUNStep

  • GNUStep是GNU計(jì)劃的項(xiàng)目之一,它將Cocoa的OC庫(kù)重新開(kāi)源實(shí)現(xiàn)了一遍,其里面有runloop、runtime等不開(kāi)源代碼的實(shí)現(xiàn)方式
  • 源碼地址:http://www.gnustep.org/resources/downloads.php
  • 雖然GNUStep不是蘋(píng)果官方源碼,但還是具有一定的參考價(jià)值
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、基礎(chǔ)概念 有4個(gè)術(shù)語(yǔ)比較容易混淆:同步、異步、并發(fā)、串行 1.進(jìn)程和線程 進(jìn)程:進(jìn)程是計(jì)算機(jī)中已運(yùn)行程序的實(shí)體...
    666真666閱讀 1,355評(píng)論 0 7
  • 章前回顧 上章我們了解了鎖的一些知識(shí),線程安全需要鎖的協(xié)助。這章我們探索一下多線程原理篇; 初識(shí) 周知,了解多線程...
    孜孜不倦_閑閱讀 607評(píng)論 0 0
  • 多線程相關(guān)知識(shí): 同步線程:dispatch中的sync函數(shù),即是在當(dāng)前線程做事情 異步函數(shù):dispatch中的...
    我是一只攻城獅_ifYou閱讀 2,455評(píng)論 0 9
  • 多線程面試題 你理解的多線程?iOS的多線程方案有哪幾種?你更傾向于哪一種?你在項(xiàng)目中用過(guò) GCD 嗎?GCD 的...
    _曾夢(mèng)想仗劍走天涯閱讀 1,090評(píng)論 0 4
  • 線程的定義 ? 線程是進(jìn)程的基本執(zhí)行單元,一個(gè)進(jìn)程的所有任務(wù)都在線程中執(zhí)行? 進(jìn)程要想執(zhí)行任務(wù),必須得有線程,進(jìn)程...
    yan0_0閱讀 697評(píng)論 0 3

友情鏈接更多精彩內(nèi)容