同步執行 + 主隊列 同步執行 + 主隊列在不同線程中調用結果也是不一樣,在主線程中調用會出現死鎖,而在其他線程中則不會。 在主線程中調用同步執行 + 主隊列 互相等待卡住不可行 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
也沒有列印。
其他線程中調用同步執行 + 主隊列
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---endView Code
結論:
- 所有任務都是在主線程(非當前線程)中執行的,沒有開啟新的線程(所有放在
主隊列
中的任務,都會放到主線程中執行)。 - 所有任務都在列印的
syncConcurrent---begin
和syncConcurrent---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之後才開始執行的(非同步執行不會做任何等待,可以繼續執行任務)。
- 任務是按順序執行的(因為主隊列是
串列隊列
,每次只有一個任務被執行,任務一個接一個按順序執行)。