GCD多線程 + 鎖機(jī)制

首先我們要搞清楚一些概念:

主線程是在可以其他隊(duì)列的任務(wù)進(jìn)行操作的
主隊(duì)列mainqueue的任務(wù)肯定在是主線程上操作的

對(duì)于串行隊(duì)列,每創(chuàng)建一個(gè)串行隊(duì)列,系統(tǒng)就會(huì)對(duì)應(yīng)創(chuàng)建一個(gè)線程,同時(shí)這些線程都是并行執(zhí)行的,只是在串行隊(duì)列中的任務(wù)是串行執(zhí)行的。大量的創(chuàng)建串行隊(duì)列會(huì)導(dǎo)致大量消耗內(nèi)存,這是不可取的做法。串行隊(duì)列的優(yōu)勢(shì)在于他是一個(gè)線程,所以在操作一個(gè)全局?jǐn)?shù)據(jù)時(shí)候是線程安全的。當(dāng)想并行執(zhí)行而不發(fā)生數(shù)據(jù)競(jìng)爭(zhēng)時(shí)候可以用并行隊(duì)列操作

如果我們cpu是單核,能不能并行操作任務(wù):不能
如果我們cpu是雙核,能不能并行操作任務(wù):能 cpu1 處理A, cpu2 處理B

串行隊(duì)列,并行隊(duì)列:
我們想象成這樣的場(chǎng)景,銀行有一個(gè)窗口
串行隊(duì)列就是需要排隊(duì)按順序辦理,在前面的就先辦理,后面的就后辦理,不能插隊(duì)
并行隊(duì)列就是他們沒有排隊(duì),完全是靠擠的,誰(shuí)先辦理也就是隨機(jī)的

串發(fā)和并發(fā):
我們想象成這樣的場(chǎng)景,串發(fā)就是只有當(dāng)前的窗口(即當(dāng)前線程,可以是主線程也可以是子線程)可以辦理,不會(huì)再開新的窗口
并發(fā)就是會(huì)再給你開多個(gè)窗口(即多個(gè)線程)辦理。

串行和串發(fā):沒有開啟新線程,任務(wù)是逐個(gè)完成的
串行和并發(fā):開啟新線程,任務(wù)是逐個(gè)完成的
并行和串發(fā):沒有開啟新線程,任務(wù)是逐個(gè)執(zhí)行
并行和并發(fā):開啟新線程,任務(wù)是并發(fā)的

串行隊(duì)列:

    dispatch_queue_t eoc_queueOneTT = dispatch_queue_create("eoc_queueOneTT", DISPATCH_QUEUE_SERIAL);

打印結(jié)果:


image.png

寬度是:0x1,因?yàn)槭谴?,所以寬度?,每次只允許一個(gè)任務(wù)進(jìn)行。

并行隊(duì)列:

    dispatch_queue_t eoc_queueOneTT = dispatch_queue_create("eoc_queueOneTT", DISPATCH_QUEUE_CONCURRENT);

打印結(jié)果:


image.png

寬度是:0xffe,因?yàn)槭遣⑿?,所以寬度不?,每次允許多個(gè)任務(wù)進(jìn)行。

串行隊(duì)列(串發(fā)即同步,并發(fā)即異步)

// 串行隊(duì)列 只能開啟一個(gè)任務(wù) (串發(fā),即同步 dispatch_sync  在當(dāng)前線程操作 sync:同步)
- (void)serialQueue{
    
    // 創(chuàng)建用戶串行隊(duì)列 serial
    dispatch_queue_t queue = dispatch_queue_create("serQueue", DISPATCH_QUEUE_SERIAL);
    // 異步
    dispatch_async(queue, ^{
        NSLog(@"1:%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2:%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3:%@", [NSThread currentThread]);
    });
    // 同步
    dispatch_sync(queue, ^{
        NSLog(@"4:%@", [NSThread currentThread]);
    });
}

輸出結(jié)果:


image.png

串行隊(duì)列就后面參數(shù)是:DISPATCH_QUEUE_SERIAL的時(shí)候。
同步和異步只是兩種方法的不同,dispatch_async異步的時(shí)候,會(huì)開啟新的線程。dispatch_sync同步的時(shí)候,就在當(dāng)前線程,即主線程。而且都是按照順序執(zhí)行的。

并行隊(duì)列(串發(fā)即同步,并發(fā)即異步)

// 并行隊(duì)列 同時(shí)可以開啟多個(gè)任務(wù) (并發(fā),即異步 dispatch_async  另外再開新的線程 async:異步)
- (void)conCurrentQueue{
    
    // 創(chuàng)建用戶串行隊(duì)列 concurrent
    dispatch_queue_t queue = dispatch_queue_create("serQueue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"1:%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2:%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"3:%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
         NSLog(@"4當(dāng)前線程:%@", [NSThread currentThread]);
    });
}

輸出結(jié)果:


image.png

并行隊(duì)列就后面參數(shù)是:DISPATCH_QUEUE_CONCURRENT的時(shí)候。
同步和異步只是兩種方法的不同,dispatch_async異步的時(shí)候,會(huì)開啟新的線程。dispatch_sync同步的時(shí)候,就在當(dāng)前線程,即主線程。但是都沒有按照順序執(zhí)行。

組(用于多個(gè)任務(wù)執(zhí)行)

- (void)group_gcd{
    // 1 創(chuàng)建組
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("serQueue", DISPATCH_QUEUE_CONCURRENT);
    // 2向組添加任務(wù)  任務(wù)數(shù)count=3
    dispatch_group_async(group, queue, ^{
        NSLog(@"task one::%@", [NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"task two::%@", [NSThread currentThread]);
    });
    dispatch_group_async(group, queue, ^{
        NSLog(@"task three::%@", [NSThread currentThread]);
    });
    
    // 3組任務(wù)全部完成了,就通知, 然后執(zhí)行下面block里面的方法  任務(wù)數(shù)count為0
    dispatch_group_notify(group, queue, ^{
        NSLog(@"finish all task");
    });
}

輸出結(jié)果:


image.png

不管前面是串行還是并行隊(duì)列,只有組里面的添加的任務(wù)數(shù)做完了,當(dāng)任務(wù)數(shù)為0的時(shí)候,才會(huì)走最后一個(gè)組通知的方法,執(zhí)行block里面的方法。

組的應(yīng)用

一個(gè)界面有多個(gè)請(qǐng)求的時(shí)候,可以用到組。當(dāng)?shù)诙€(gè)網(wǎng)絡(luò)請(qǐng)求里面可能用到第一個(gè)請(qǐng)求成功里面的數(shù)據(jù),就要等第一個(gè)請(qǐng)求成功過后,才能執(zhí)行第二個(gè)請(qǐng)求,類似這樣的情況。

// 一個(gè)界面執(zhí)行加載多個(gè)網(wǎng)絡(luò)請(qǐng)求,可以用到group
- (void)groupStyleTwo{
    // 1 創(chuàng)建組
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_queue_create("serQueue", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 3; i++) {
        
        // 填加一個(gè)空任務(wù),讓任務(wù)數(shù)+1,當(dāng)任務(wù)完成后,再移除空任務(wù),讓任務(wù)數(shù)-1,最后任務(wù)數(shù)為0的時(shí)候,才會(huì)走通知的方法
        // 或者用最下面注釋的那三行寫法,效果也是一樣的
        dispatch_group_enter(group); // 任務(wù)數(shù)+1
        dispatch_async(queue, ^{
            [self netLoadSync:i]; // 如果在這個(gè)任務(wù)再開一個(gè)線程,那么不能保證你的需求
            dispatch_group_leave(group);// 任務(wù)數(shù)-1
        });
        
//        dispatch_group_async(group, queue, ^{
//            [self netLoadSync:i];
//        });
    }
    // 3組任務(wù)全部完成了,就通知
    dispatch_group_notify(group, queue, ^{
        NSLog(@"finish all task");
    });
}

// task 同步
- (void)netLoadSync:(int)taskCount
{
    NSString *urlPath = @"http://svr.tuliu.com/center/front/app/util/updateVersions";
    NSString *urlstr = [NSString stringWithFormat:@"%@?versions_id=1&system_type=1", urlPath];
    NSURL *url = [NSURL URLWithString:urlstr];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];
    
    // 創(chuàng)建信號(hào)量,做標(biāo)記,當(dāng)請(qǐng)求成功并完成過后,才執(zhí)行后面的代碼
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);  // 信號(hào)量 - 1
    NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error){
      //  NSDictionary *infoDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
        NSLog(@"完成了,taskcount:%d", taskCount);
        // 完成過后,發(fā)生信號(hào)量
        dispatch_semaphore_signal(sema);  // 信號(hào)量 - 2
        
    }];
    [task resume];
    // 阻塞代碼,達(dá)到同步的效果,直到收到信號(hào)量(收到信號(hào)量,也就是說請(qǐng)求完成了),才繼續(xù)執(zhí)行
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);  // 信號(hào)量 - 3
    NSLog(@"finish 代碼跑完了:%d",taskCount);
}

輸出結(jié)果:


組的應(yīng)用結(jié)果1

我們?yōu)榱诉_(dá)到同步的效果,使用了信號(hào)量(代碼中關(guān)于信號(hào)量的那三行代碼),即只有請(qǐng)求成功過后,才會(huì)執(zhí)行請(qǐng)求后面的代碼,以免出現(xiàn)一些錯(cuò)誤,后面要跟上一堆判斷請(qǐng)求是否成功。

如果不加那三行信號(hào)量的代碼,輸出結(jié)果如下:


組的應(yīng)用結(jié)果2

柵欄

- (void)barrier_fct{
    
    dispatch_queue_t queue = dispatch_queue_create("serQueue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"分界線前:taskOne");
    });
    dispatch_async(queue, ^{
        NSLog(@"分界線前:taskTwo");
    });
    dispatch_async(queue, ^{
        NSLog(@"分界線前:taskThree");
    });
    dispatch_barrier_async(queue, ^{ // 分界線里面,queue可以看作是串行的,當(dāng)前只能執(zhí)行barrier里面的task
        NSLog(@"分界線里面的任務(wù)");
    });
    dispatch_async(queue, ^{
        NSLog(@"分界線后:taskFour");
    });
    dispatch_async(queue, ^{
        NSLog(@"分界線后:taskFive");
    });
    // 可以看成三個(gè)部分,分界線前面三個(gè)是一個(gè)部分,分界線里面是第二個(gè)部分,分界線后面兩個(gè)是第三個(gè)部分。而且必須是第一部分執(zhí)行完了,才能執(zhí)行第二部分,第二部分執(zhí)行完了,才能執(zhí)行第三部分。
}

輸出結(jié)果:


image.png

柵欄的應(yīng)用

讀寫數(shù)組 mutableAry,如果開幾個(gè)線程來操作數(shù)組
1 寫數(shù)組(移除index=0對(duì)象), 2 寫數(shù)組(移除了index=0的對(duì)象) // 有問題
1 讀數(shù)組 2 讀數(shù)組 // 沒問題
1 讀數(shù)組 2寫數(shù)組
只要涉及到寫操作(要做保護(hù)),當(dāng)數(shù)組寫的時(shí)候,不允許其他線程對(duì)它有操作,不然就會(huì)有問題。

- (void)viewDidLoad {
    [super viewDidLoad];
    _safeAry = [NSMutableArray array];
    [_safeAry addObject:@"0"];
    [_safeAry addObject:@"1"];
    [_safeAry addObject:@"2"];
    [_safeAry addObject:@"3"];
    rwQueue = dispatch_queue_create("serQueue", DISPATCH_QUEUE_CONCURRENT);
}
- (void)testRWAry{
    
    dispatch_queue_t queue = dispatch_queue_create("testRWAry", DISPATCH_QUEUE_CONCURRENT);
    for (int i = 0; i < 20; i++) {
        // 讀
        dispatch_async(queue, ^{
            NSLog(@"%d::%@", i, [self indexTo:i]);
        });
        // 寫
        dispatch_async(queue, ^{
            [self addObject:[NSString stringWithFormat:@"%d", i+4]];
        });
    }
    
}
// 寫 保證只有一個(gè)在操作,所以是把這個(gè)操作放在柵欄里面,而不是它的前面或者后面,因?yàn)楫?dāng)執(zhí)行柵欄里面操作的時(shí)候,就只有它在執(zhí)行(避免了同時(shí)多個(gè)寫操作導(dǎo)致的問題)
- (void)addObject:(NSString*)object{
    
    dispatch_barrier_async(rwQueue, ^{
        if (object != nil) {
            [_safeAry addObject:object];
        }
    });
    
}
// 主隊(duì)列 mainqueue --> 主線程 mainThread
// 注意同步dispatch_sync,因?yàn)闃I(yè)務(wù)關(guān)系,必須馬上數(shù)據(jù),所以不能異步
- (NSString*)indexTo:(NSInteger)index{
    __block NSString *result = nil;
    dispatch_sync(rwQueue, ^{
        if (index < _safeAry.count) {
            result = _safeAry[index];
        }
    });
    return result;
}

輸出結(jié)果:


image.png

重復(fù) 執(zhí)行任務(wù)

- (void)apply_gcd{
    
    dispatch_queue_t queue = dispatch_queue_create("testRWAry", DISPATCH_QUEUE_CONCURRENT);
   // 第一個(gè)參數(shù)是重復(fù)的次數(shù)
    dispatch_apply(5, queue , ^(size_t count) {
        NSLog(@"%zu", count);
    });
}

輸出結(jié)果:


image.png

延后 執(zhí)行任務(wù)

- (void)after_GCD{
    
    dispatch_queue_t queue = dispatch_queue_create("testRWAry", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"start:%@", [NSThread currentThread]);
        // 又重新開啟了一個(gè)線程來執(zhí)行延后的操作,所以不需要開啟RunLoop
        dispatch_after(1, queue, ^{
            NSLog(@"dispatch_after:%@", [NSThread currentThread]);
        });
        NSLog(@"end");
        
    });
}
   //只能延后執(zhí)行,不能設(shè)置延后多少秒執(zhí)行

輸出結(jié)果:


image.png

激活

注意一開始創(chuàng)建隊(duì)列,要?jiǎng)?chuàng)建成INACTIVE的

- (void)queueInactive{
    
    // INACTIVE 未激活的,添加任務(wù)后不會(huì)自動(dòng)執(zhí)行,需要我們手動(dòng)激活過后才會(huì)執(zhí)行
    dispatch_queue_t queue = dispatch_queue_create("testRWAry", DISPATCH_QUEUE_CONCURRENT_INACTIVE);
    dispatch_async(queue, ^{
        NSLog(@"start:%@", [NSThread currentThread]);
    });
    // 激活
    dispatch_activate(queue);
}

傳函數(shù)指針 _f IMP

void testFunction(){
    NSLog(@"testFunction::-->%@", [NSThread currentThread]);
}
// _f IMP
- (void)function_f{
    dispatch_queue_t queue = dispatch_queue_create("testRWAry", DISPATCH_QUEUE_CONCURRENT);
    // 第三個(gè)參數(shù)是需要傳函數(shù)指針
    dispatch_async_f(queue, nil, testFunction);
}

GCD定時(shí)器

@implementation GCDTwoViewVC
- (void)viewDidLoad {
    [super viewDidLoad];
    queue = dispatch_queue_create("eoc_queue", DISPATCH_QUEUE_CONCURRENT);
    [self timeSource];
}

// 定時(shí)器  unix (pthread) GCD()
dispatch_source_t soure;
- (void)timeSource{

    // source關(guān)聯(lián)到隊(duì)列
    soure = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    // 配置soure的時(shí)間
    /*
     GCD的時(shí)間參數(shù),一般是納秒(1秒 == 10的9次方納秒) 所以要乘上 NSEC_PER_SEC
     第二個(gè)參數(shù):馬上觸發(fā)
     第三個(gè)參數(shù):間隔一秒
     第四個(gè)參數(shù):誤差一秒
     */
    dispatch_source_set_timer(soure, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
    // 配置source的處理事件
    dispatch_source_set_event_handler(soure, ^{
        NSLog(@"soure_event:==%@", [NSThread currentThread]);
    });
    // 開啟定時(shí)器
    dispatch_resume(soure);
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    
    // 暫停定時(shí)器
//    dispatch_suspend(soure);
    // 取消定時(shí)器
    dispatch_cancel(soure);
}
@end

信號(hào)量 + 互斥鎖 -> 造成死鎖

在互斥鎖里面使用了信號(hào)量,容易造成死鎖的情況,當(dāng)信號(hào)量阻塞了過后,不能解鎖,也就進(jìn)行不到下一步。

#import "SignalLock.h"
#import <pthread.h>

@interface SignalLock (){
    NSLock *mutexLock;
    dispatch_semaphore_t sema;
    int count;
}
@end

@implementation SignalLock

- (instancetype)init{
    self = [super init];
    if (self) {
        mutexLock = [NSLock new];
        sema = dispatch_semaphore_create(0);
    }
    return self;
}

- (void)signalLock{
    [NSThread detachNewThreadSelector:@selector(threadOne) toTarget:self withObject:nil];
    [NSThread detachNewThreadSelector:@selector(threadTwo) toTarget:self withObject:nil];
}

- (void)threadOne{
    [self signalLockWrite];
}
- (void)threadTwo{
     [self signalLockRead];
}

#pragma mark -  信號(hào)量+ 互斥鎖(死鎖)
///////// 信號(hào)量 + 互斥鎖(死鎖)
- (void)signalLockWrite{
    
    while (1) {
        // 上鎖
        [mutexLock lock];
        if (count >= 10) {
            // 沒有內(nèi)存了
            NSLog(@"空間滿了");
            // 信號(hào)量阻塞,等待
            // 因?yàn)檫@邊已經(jīng)上鎖了,還沒有解鎖,所以你這里阻塞了過后,不能走到下面方法的dispatch_semaphore_signal,釋放空間
            dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); // 阻塞
        }else{
            
            count++;
            NSLog(@"空間:%d", count);
        }
        // 解鎖
        [mutexLock unlock];
    }
}
- (void)signalLockRead{
    while (1) {
        // 上鎖
        [mutexLock lock];
        if (count >= 10) {
            count--;
            NSLog(@"釋放空間");
            // 當(dāng)上面上了鎖,并用信號(hào)量阻塞了過后,沒有解鎖,就走不到這個(gè)方法來
            dispatch_semaphore_signal(sema);
        }else{
            count++;
        }
        // 解鎖
        [mutexLock unlock];
    }
}
@end

打印如下:


死鎖

空間滿了過后,不能走到下一步的釋放空間。

條件量

為了解決上面的死鎖問題可以用條件量來解決,條件量有兩種OC的條件量和C的條件量,其中C的條件量要和C的互斥鎖結(jié)合起來使用。

#import "C_ConditionLock.h"
#import <pthread.h>

@interface C_ConditionLock(){
    // OC的條件量
    NSCondition *_condition;
    int count;

    // C的互斥鎖
    pthread_mutex_t mutex; // NSLock OC的互斥鎖
    // C的條件量
    pthread_cond_t cond;
}

@end;

@implementation C_ConditionLock

- (instancetype)init
{
    self = [super init];
    if (self) {
        //初始化OC的條件量
        _condition = [NSCondition new];
        count = 0;
        
        //初始化C的互斥鎖和條件量
        pthread_mutex_init(&mutex, 0);
        pthread_cond_init(&cond, 0);
    }
    return self;
}

- (void)signalLock{
    [NSThread detachNewThreadSelector:@selector(threadOne) toTarget:self withObject:nil];
    [NSThread detachNewThreadSelector:@selector(threadTwo) toTarget:self withObject:nil];
}

- (void)conditionLockTheory{
    [NSThread detachNewThreadSelector:@selector(conditionLockOne) toTarget:self withObject:nil];
    [NSThread detachNewThreadSelector:@selector(conditionLockTwo) toTarget:self withObject:nil];
}

- (void)threadOne{
    [self signalLockWrite];
}


- (void)threadTwo{
    
    [self signalLockRead];
}

#pragma mark -  OC條件量
- (void)signalLockWrite{
    
    while (1) {
        [_condition lock];
        if (count >= 10) {
            // 沒有內(nèi)存了
            NSLog(@"空間滿了");
            [_condition wait];
        }else{
            count++;
        }
        [_condition unlock];
    }
}

- (void)signalLockRead{
    
    while (1) {
        [_condition lock];
        if (count >= 10) {
            count--;
            NSLog(@"釋放空間");
            [_condition signal];
        }else{
            count++;
        }
        [_condition unlock];
    }
}

#pragma mark -  OC條件量, C的實(shí)現(xiàn)
- (void)conditionLockOne{
    while (1) {
        // 上鎖
        pthread_mutex_lock(&mutex);
        if (count >= 10) {
            // 沒有內(nèi)存了
            NSLog(@"空間滿了");
            // 阻塞,等待
            pthread_cond_wait(&cond, &mutex);// 阻塞 但是互斥鎖(mutex)這個(gè)解了,即可以進(jìn)行下面的方法了,沒有被鎖住了
        }else{
            count++;
        }
        // 解鎖
        pthread_mutex_unlock(&mutex);
    }
}

- (void)conditionLockTwo
{
    while (1) {
        
        pthread_mutex_lock(&mutex);
        if (count >= 10) {
            count--;
            NSLog(@"釋放空間");
            // 發(fā)送信號(hào)
            pthread_cond_signal(&cond);
        }else{
            count++;
        }
        pthread_mutex_unlock(&mutex);
    }
}

@end

打印結(jié)果:


條件量

這樣當(dāng)空間滿了過后,就能夠釋放空間,不會(huì)造成死鎖

遞歸鎖

遞歸鎖也有OC和C兩種實(shí)現(xiàn)

#import "RecursiveLock.h"
#import <pthread.h>

/*
 OC的鎖基于c的封裝,鎖對(duì)象化了
 */

@implementation RecursiveLock{
    
}

- (instancetype)init{
    
    self = [super init];
    if (self) {
        [self oc_recursiveLockinit];
        [self c_recursiveLockinit];
    }
    return self;
}

- (void)oc_recursiveLockinit{
    // OC遞歸鎖的初始化
    recursiveLock = [[NSRecursiveLock alloc] init];
}

- (void)c_recursiveLockinit{
    // C遞歸鎖的初始化
    pthread_mutexattr_t attr;
    pthread_mutexattr_init (&attr);
    pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init (&_reclock, &attr);
    pthread_mutexattr_destroy (&attr);
}

// 遞歸鎖 OC
- (void)recursiveLock{
    NSLog(@"start");
    NSLog(@"result:%d", [self addCount:10]);
    NSLog(@"end");
}

// 遞歸鎖 C
- (void)recursiveLockTheory{
    NSLog(@"theory start");
    NSLog(@"theory result:%d", [self addC__Count:10]);
    NSLog(@"theory end");
}
// 遞歸里面做安全策略,用互斥鎖會(huì)造成死鎖的
// 遞歸鎖里可以累加鎖的數(shù)量,只要最后加鎖和解鎖數(shù)量是一樣的,就不會(huì)造成死鎖
- (int)addCount:(int)count{
    // 互斥鎖,下面這行代碼連續(xù)執(zhí)行兩次就會(huì)造成死鎖
    [recursiveLock lock];
    if (count < 1) {
        return count;
    }
    __block int tmp;
    NSLog(@"count::%d", count);
    tmp = count + [self addCount:count-1];
    [recursiveLock unlock];
    return tmp;
}

// C 里面遞歸鎖的實(shí)現(xiàn)
- (int)addC__Count:(int)count{
    pthread_mutex_lock(&_reclock);
    if (count < 1) {
        return count;
    }
    __block int tmp;
    NSLog(@"theory count::%d", count);
    tmp = count + [self addC__Count:count-1];
    pthread_mutex_unlock(&_reclock);
    return tmp;
}
@end

OC的鎖基于C的封裝,只是將鎖對(duì)象化了。

參考文章:
iOS主線程和主隊(duì)列的區(qū)別
IOS GCD線程相關(guān)內(nèi)容(dispatch_sync,dispatch_async)
GCD 學(xué)習(xí)(二)dispatch_queue_create創(chuàng)建Dispatch Queue

最后編輯于
?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 從哪說起呢? 單純講多線程編程真的不知道從哪下嘴。。 不如我直接引用一個(gè)最簡(jiǎn)單的問題,以這個(gè)作為切入點(diǎn)好了 在ma...
    Mr_Baymax閱讀 2,917評(píng)論 1 17
  • GCD全稱Grand Central Dispatch,從名稱可以看出GCD就是起到中央調(diào)度的作用。這個(gè)調(diào)度作用就...
    _小沫閱讀 1,095評(píng)論 1 8
  • 程序中同步和異步是什么意思?有什么區(qū)別? 解釋一:異步調(diào)用是通過使用單獨(dú)的線程執(zhí)行的。原始線程啟動(dòng)異步調(diào)用,異步調(diào)...
    風(fēng)繼續(xù)吹0閱讀 1,121評(píng)論 1 2
  • iOS多線程編程 基本知識(shí) 1. 進(jìn)程(process) 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序,就是一段程序的執(zhí)...
    陵無山閱讀 6,362評(píng)論 1 14
  • 1. “日月同輝”說的是太陽(yáng)和月亮同時(shí)出現(xiàn)在天上。但楚云現(xiàn)在看到的,是太陽(yáng)掛在天上,月亮出現(xiàn)在水里,水里的月亮發(fā)著...
    殼_殼閱讀 589評(píng)論 7 2

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