• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Harley
博客园    首页    新随笔    联系   管理    订阅  订阅

GCD(II)

主队列

组队列是串行队列,全局队列属于并发队列。

同步执行 + 主队列

同步执行 + 主队列在不同线程中调用结果也是不一样,在主线程中调用会出现死锁,而在其他线程中则不会。

在主线程中调用同步执行 + 主队列

互相等待卡住不可行

 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---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之后才开始执行的(异步执行不会做任何等待,可以继续执行任务)。
  • 任务是按顺序执行的(因为主队列是串行队列,每次只有一个任务被执行,任务一个接一个按顺序执行)。

 

 

上一篇:GCD(I)

下一篇:GCD(III) 

posted @ 2018-03-28 11:06  Harely  阅读(47)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3