GCD(II)

来源:https://www.cnblogs.com/EchoHG/archive/2018/03/28/8662633.html
-Advertisement-
Play Games

同步執行 + 主隊列 同步執行 + 主隊列在不同線程中調用結果也是不一樣,在主線程中調用會出現死鎖,而在其他線程中則不會。 在主線程中調用同步執行 + 主隊列 互相等待卡住不可行 1 - (void)syncMain { 2 3 NSLog(@"currentThread %@",[NSThread ...


主隊列

組隊列是串列隊列,全局隊列屬於併發隊列。

同步執行 + 主隊列

同步執行 + 主隊列在不同線程中調用結果也是不一樣,在主線程中調用會出現死鎖,而在其他線程中則不會。

在主線程中調用同步執行 + 主隊列

互相等待卡住不可行

 1 - (void)syncMain {
 2     
 3     NSLog(@"currentThread---%@",[NSThread currentThread]);  // 列印當前線程
 4     NSLog(@"syncMain---begin");
 5     
 6     dispatch_queue_t queue = dispatch_get_main_queue();
 7     
 8     dispatch_sync(queue, ^{
 9         // 追加任務1
10         for (int i = 0; i < 2; ++i) {
11             [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
12             NSLog(@"1---%@",[NSThread currentThread]);      // 列印當前線程
13         }
14     });
15     
16     dispatch_sync(queue, ^{
17         // 追加任務2
18         for (int i = 0; i < 2; ++i) {
19             [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
20             NSLog(@"2---%@",[NSThread currentThread]);      // 列印當前線程
21         }
22     });
23     
24     dispatch_sync(queue, ^{
25         // 追加任務3
26         for (int i = 0; i < 2; ++i) {
27             [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
28             NSLog(@"3---%@",[NSThread currentThread]);      // 列印當前線程
29         }
30     });
31     
32     NSLog(@"syncMain---end");
33 }
View Code

 

列印結果:

1 2018-03-28 10:58:43.954991+0800 StruggleSwift[1461:28157] currentThread---<NSThread: 0x60c000074d40>{number = 1, name = main}
2 2018-03-28 10:58:44.592754+0800 StruggleSwift[1461:28157] syncMain---begin
3 (lldb) 

 

死鎖圖:

 

現象:

在主線程中使用同步執行 + 主隊列,追加到主線程的任務1、任務2、任務3都不再執行了,而且syncMain---end也沒有列印,在XCode 9上還會報崩潰。這是為什麼呢?

原因:是queue 和 任務 1相互等待造成的。

我們在主線程中執行syncMain方法,相當於把syncMain任務放到了主線程的隊列中。而同步執行會等待當前隊列中的任務執行完畢,才會接著執行。那麼當我們把任務1追加到主隊列中,任務1就在等待主線程處理完syncMain任務。而syncMain任務需要等待任務1執行完畢,才能接著執行。

那麼,現在的情況就是syncMain任務和任務1都在等對方執行完畢。這樣大家互相等待,所以就卡住了,所以我們的任務執行不了,而且syncMain---end也沒有列印。

  解決辦法:將同步sync 改為 async。 主隊列和 任務1 必須等待主線程中的任務走完才能走添加到主隊列中的任務。

其他線程中調用同步執行 + 主隊列

 1 //其他線程中調用 同步執行 + 主隊列
 2 - (void)otherThreadExecuteForSyncMain {
 3 //    使用 NSThread 的 detachNewThreadSelector 方法會創建線程,並自動啟動線程執行 selector 任務
 4     [NSThread detachNewThreadSelector:@selector(syncMain) toTarget:self withObject:nil];
 5 }
 6 
 7 
 8 //主線程中調用 同步執行 + 主隊列
 9 - (void)syncMain {
10     
11     NSLog(@"currentThread---%@",[NSThread currentThread]);  // 列印當前線程
12     NSLog(@"syncMain---begin");
13     
14     dispatch_queue_t queue = dispatch_get_main_queue();
15     
16     dispatch_sync(queue, ^{
17         // 追加任務1
18         for (int i = 0; i < 2; ++i) {
19             [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
20             NSLog(@"1---%@",[NSThread currentThread]);      // 列印當前線程
21         }
22     });
23     
24     dispatch_sync(queue, ^{
25         // 追加任務2
26         for (int i = 0; i < 2; ++i) {
27             [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
28             NSLog(@"2---%@",[NSThread currentThread]);      // 列印當前線程
29         }
30     });
31     
32     dispatch_sync(queue, ^{
33         // 追加任務3
34         for (int i = 0; i < 2; ++i) {
35             [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
36             NSLog(@"3---%@",[NSThread currentThread]);      // 列印當前線程
37         }
38     });
39     
40     NSLog(@"syncMain---end");
41 }
View Code

 

列印結果:

 1 <-------------------------線程結束-------------------------->
 2 2018-03-28 14:07:48.676276+0800 StruggleSwift[4834:178554] [BoringSSL] Function boringssl_session_errorlog: line 2871 [boringssl_session_read] SSL_ERROR_ZERO_RETURN(6): operation failed because the connection was cleanly shut down with a close_notify alert
 3 2018-03-28 14:07:48.678295+0800 StruggleSwift[4834:179375] currentThread---<NSThread: 0x60c000272bc0>{number = 7, name = (null)}
 4 2018-03-28 14:07:48.680254+0800 StruggleSwift[4834:178554] [BoringSSL] Function boringssl_session_errorlog: line 2871 [boringssl_session_read] SSL_ERROR_ZERO_RETURN(6): operation failed because the connection was cleanly shut down with a close_notify alert
 5 2018-03-28 14:07:49.436085+0800 StruggleSwift[4834:179375] syncMain---begin
 6 2018-03-28 14:08:12.947550+0800 StruggleSwift[4834:178356] 1---<NSThread: 0x6000000760c0>{number = 1, name = main}
 7 2018-03-28 14:08:17.442346+0800 StruggleSwift[4834:178356] 1---<NSThread: 0x6000000760c0>{number = 1, name = main}
 8 2018-03-28 14:08:28.777947+0800 StruggleSwift[4834:178356] 2---<NSThread: 0x6000000760c0>{number = 1, name = main}
 9 2018-03-28 14:08:30.779303+0800 StruggleSwift[4834:178356] 2---<NSThread: 0x6000000760c0>{number = 1, name = main}
10 2018-03-28 14:08:37.444289+0800 StruggleSwift[4834:178356] 3---<NSThread: 0x6000000760c0>{number = 1, name = main}
11 2018-03-28 14:08:39.445499+0800 StruggleSwift[4834:178356] 3---<NSThread: 0x6000000760c0>{number = 1, name = main}
12 2018-03-28 14:08:40.512798+0800 StruggleSwift[4834:179375] syncMain---end
View Code

 

結論:

  • 所有任務都是在主線程(非當前線程)中執行的,沒有開啟新的線程(所有放在主隊列中的任務,都會放到主線程中執行)。
  • 所有任務都在列印的syncConcurrent---beginsyncConcurrent---end之間執行(同步任務需要等待隊列的任務執行結束)。
  • 任務是按順序執行的(主隊列是串列隊列,每次只有一個任務被執行,任務一個接一個按順序執行)。

為什麼現在就不會卡住了呢?
因為syncMain 任務放到了其他線程里,而任務1任務2任務3都在追加到主隊列中,這三個任務都會在主線程中執行。syncMain 任務在其他線程中執行到追加任務1到主隊列中,因為主隊列現在沒有正在執行的任務,所以,會直接執行主隊列的任務1,等任務1執行完畢,再接著執行任務2任務3。所以這裡不會卡住線程。

 

 

非同步執行 + 主隊列

 1 //        非同步執行 + 主隊列
 2         gcd.asyncMain()
 3         
 4         print("<-------------------------線程結束-------------------------->")
 5 
 6 
 7 //非同步執行 + 主隊列
 8 - (void)asyncMain {
 9     NSLog(@"currentThread---%@",[NSThread currentThread]);  // 列印當前線程
10     NSLog(@"asyncMain---begin");
11     
12     dispatch_queue_t queue = dispatch_get_main_queue();
13     
14     dispatch_async(queue, ^{
15         // 追加任務1
16         for (int i = 0; i < 2; ++i) {
17             [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
18             NSLog(@"1---%@",[NSThread currentThread]);      // 列印當前線程
19         }
20     });
21     
22     dispatch_async(queue, ^{
23         // 追加任務2
24         for (int i = 0; i < 2; ++i) {
25             [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
26             NSLog(@"2---%@",[NSThread currentThread]);      // 列印當前線程
27         }
28     });
29     
30     dispatch_async(queue, ^{
31         // 追加任務3
32         for (int i = 0; i < 2; ++i) {
33             [NSThread sleepForTimeInterval:2];              // 模擬耗時操作
34             NSLog(@"3---%@",[NSThread currentThread]);      // 列印當前線程
35         }
36     });
37     
38     NSLog(@"asyncMain---end");
39 }
View Code

 

列印結果:

 1 2018-03-28 16:51:52.494812+0800 StruggleSwift[11744:343710] currentThread---<NSThread: 0x604000261a00>{number = 1, name = main}
 2 2018-03-28 16:51:52.495049+0800 StruggleSwift[11744:343710] asyncMain---begin
 3 2018-03-28 16:52:01.891018+0800 StruggleSwift[11744:343710] asyncMain---end
 4 <-------------------------線程結束-------------------------->
 5 2018-03-28 16:52:01.891399+0800 StruggleSwift[11744:344217] [BoringSSL] Function boringssl_session_errorlog: line 2871 [boringssl_session_read] SSL_ERROR_ZERO_RETURN(6): operation failed because the connection was cleanly shut down with a close_notify alert
 6 2018-03-28 16:52:01.891690+0800 StruggleSwift[11744:344217] [BoringSSL] Function boringssl_session_errorlog: line 2871 [boringssl_session_read] SSL_ERROR_ZERO_RETURN(6): operation failed because the connection was cleanly shut down with a close_notify alert
 7 2018-03-28 16:52:10.303745+0800 StruggleSwift[11744:343710] 1---<NSThread: 0x604000261a00>{number = 1, name = main}
 8 2018-03-28 16:52:12.305159+0800 StruggleSwift[11744:343710] 1---<NSThread: 0x604000261a00>{number = 1, name = main}
 9 2018-03-28 16:52:17.683466+0800 StruggleSwift[11744:343710] 2---<NSThread: 0x604000261a00>{number = 1, name = main}
10 2018-03-28 16:52:19.684801+0800 StruggleSwift[11744:343710] 2---<NSThread: 0x604000261a00>{number = 1, name = main}
11 2018-03-28 16:52:24.047373+0800 StruggleSwift[11744:343710] 3---<NSThread: 0x604000261a00>{number = 1, name = main}
12 2018-03-28 16:52:26.047712+0800 StruggleSwift[11744:343710] 3---<NSThread: 0x604000261a00>{number = 1, name = main}
View Code

列印結果看本質:

  • 所有任務都是在當前線程(主線程)中執行的,並沒有開啟新的線程(雖然非同步執行具備開啟線程的能力,但因為是主隊列,所以所有任務都在主線程中)。
  • 所有任務是在列印的syncConcurrent---begin和syncConcurrent---end之後才開始執行的(非同步執行不會做任何等待,可以繼續執行任務)。
  • 任務是按順序執行的(因為主隊列是串列隊列,每次只有一個任務被執行,任務一個接一個按順序執行)。

 

 

上一篇:GCD(I)

下一篇:GCD(III) 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • RadioButton的圖標大小並沒有相應的佈局參數,本文通過自定義屬性的方式自定義RadioButton,實現控製圖片大小。 ...
  • 一、介紹 最近一直在做有關JavaScriptCore的技術需求,上周發現一個問題,當在JavaScriptCore在垃圾回收時,項目會有一定幾率發生崩潰。崩潰發生時調用堆棧如下: 圖1 調用堆棧 圖1 調用堆棧 先對上圖中兩個比較重要的堆棧過程做個說明: 圖2 生成JSValue 圖2 生成JSV ...
  • 一、position和anchorPoint 1.簡單介紹 CALayer有2個非常重要的屬性:position和anchorPoint @property CGPoint position; 用來設置CALayer在父層中的位置 以父層的左上角為原點(0, 0) @property CGPoint ...
  • iOS的記憶體管理,相信大家都不陌生,之前是使用的MRC,由開發人員手動來管理記憶體,後來使用了ARC,來由系統管理記憶體。本文主要講講Autorelease,Core Foundation對象在記憶體管理方面要註意的地方。 Autorelease 提到記憶體管理,就不得不提autorelease,雖然我們平 ...
  • 入駐博客園兩個月今天第一次發隨筆,,話不多說,直接上圖展示效果 主界面用的RecyclerView的瀑布流(StaggeredGridLayoutManager),同時加上Floatbutton懸浮按鈕 此頁面是添加內容的頁面,圖中橫線框是重寫了EditText控制項達到的效果,挺簡陋的。。。 這裡集 ...
  • 為了對抗微信小程式,安卓手機廠商聯合起來推出了快應用,這是好事一件,但快應用的實現方式在我看來並不是一個最佳的方案。 ...
  • 1 //將UTCDate(世界標準時間)轉化為當地時區的標準Date(鐘錶顯示的時間) 2 //NSDate *date = [NSDate date]; 2018-03-27 06:54:41 +0000 3 //轉化後:2018-03-27 14:54:41 +0000 4 -(NSDate *... ...
  • 合成兩張圖片,上下疊加的效果: ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...