IOS 多線程信號量的用法(解決異步線程中的線程等待問題)

hello,各位讀者,我又回來了啦,感覺上一篇的文章各位的反映還算不錯,感謝各位讓我有堅持寫作的動力。好了,前話就說這么多了,開始我們今天要說的主題了,最近博主在開發(fā)中碰到一個問題,開啟兩個主要異步線程,兩個異步線程內(nèi)部又得分別開啟一個異步線程和其他耗時操作,最后還有第三個線程,這第三個線程必須等到前兩個主要線程內(nèi)部所有操作都完成以后再去執(zhí)行,但是在執(zhí)行以上這些操作的時候不能卡住界面,以下是我簡單畫的一個需求分析圖

需求分析圖

可能有些讀者一眼看下去,會覺得這不是一個簡單的線程組能搞掂的事情嘛?也許是的,那么我們來嘗試一下,對需求進行線程組的功能制作

1.第一個主要線程

dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.baidu.com"]];
    NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
      // 請求完成,可以通知界面刷新界面等操作
      NSLog(@"第一步網(wǎng)絡請求完成");
    }];
    [task resume];
      // 以下還要進行一些其他的耗時操作
      NSLog(@"耗時操作繼續(xù)進行");
});

2.第二個主要線程(跟第一線程的操作是一樣的。但是請求的地址不一樣)

dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.github.com"]];
    NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
      // 請求完成,可以通知界面刷新界面等操作
      NSLog(@"第二步網(wǎng)絡請求完成");
    }];
    [task resume];
      // 以下還要進行一些其他的耗時操作
      NSLog(@"耗時操作繼續(xù)進行");
});

3.第三個主要線程(等待前兩個線程完全完成后再進行)

dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    NSLog(@"刷新界面等在主線程的操作");
});

那么,上面代碼一眼看下去就很明了了,開啟一個線程組,然后兩個異步線程組 dispatch_group_t,最后一個 dispatch_group_notify 來執(zhí)行依賴操作,但是當博主開開心心的跑去 command + R 的時候,奇怪的事情發(fā)生了,以下是是輸出的結果:

1 `NSLog(@"第一步網(wǎng)絡請求完成");`
2 `NSLog(@"刷新界面等在主線程的操作");`
3 `NSLog(@"第二步網(wǎng)絡請求完成");`

讀者不難發(fā)現(xiàn),我們的數(shù)序不對了,第三步操作(刷新界面操作)明明是要第一步和第二步操作完成后才能進行的,我們已經(jīng)設置了 dispatch_group_notify 了,但是為什么不是按照我們的思路去走呢?
其實這個道理很簡單,我們開啟的網(wǎng)絡請求,是一個異步線程,所謂的異步線程,就是告訴系統(tǒng)你不要管我是否完成了,你盡管執(zhí)行其他操作,開一個線程讓我到外面操作去執(zhí)行就行了,所以我們傻傻的 dispatch_group_async 自然就不會管網(wǎng)絡操作是否完成,是否有數(shù)據(jù)了,直接執(zhí)行下面操作,告訴 dispatch_group_notify 它已經(jīng)完成就行了。


但這怎么辦好呢?所以我們要引入了我們今天要用到的 多線程的信號量 dispatch_semaphore_t 了,那么 dispatch_semaphore_t又怎么理解么?

` dispatch_semaphore_t` :通俗的說我們可以理解成他是一個紅綠燈的信號,當它的信號量為0時(紅燈)等待,
  當信號量為1或大于1時(綠燈)走。

以下就是它的創(chuàng)建跟使用:

// 創(chuàng)建一個信號,value:信號量
dispatch_semaphore_create(<#long value#>)
// 使某個信號的信號量+1
dispatch_semaphore_signal(<#dispatch_semaphore_t dsema#>)
// 某個信號進行等待, timeout:等待時間,永遠等待為 DISPATCH_TIME_FOREVER
dispatch_semaphore_wait(<#dispatch_semaphore_t dsema#>, <#dispatch_time_t timeout#>)

那么我們的代碼可以改寫為

// 設置一個異步線程組
dispatch_group_async(group, dispatch_queue_create("com.dispatch.test", DISPATCH_QUEUE_CONCURRENT), ^{
    // 設置一個網(wǎng)絡請求
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://www.github.com"]];
    // 創(chuàng)建一個信號量為0的信號(紅燈)
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    NSURLSessionDownloadTask *task = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSLog(@"第一步操作");
        // 使信號的信號量+1,這里的信號量本來為0,+1信號量為1(綠燈)
        dispatch_semaphore_signal(sema);
    }];
    [task resume];
     // 以下還要進行一些其他的耗時操作
      NSLog(@"耗時操作繼續(xù)進行");
    // 開啟信號等待,設置等待時間為永久,直到信號的信號量大于等于1(綠燈)
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
});

根據(jù)上面的寫法,當線程執(zhí)行到 dispatch_semaphore_wait 的時候如果網(wǎng)絡請求還沒有完成,那么信號就會繼續(xù)等待,這個異步線程組就不會執(zhí)行完畢,這樣就能達到我們的需求了。

  當然  `dispatch_semaphore_signal` 的用途可不止這么一個喔,有興趣的讀者可以去多看看喔。

@end

 最后感謝各位對我的支持,雖然不定期更新技術博客,但是我希望更新的博客都是精品,我會盡量寫得更通俗
 易懂的,給 IOS 開發(fā)的各位朋友,共勉一下啊。
 令缺勿濫。

心如止水,奮力前行

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

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