dispatch_queue_t queue = dispatch_queue_create("serial", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"sync1:%@", [NSThread currentThread]);
});
输出 sync1:<NSThread: 0x7fa731f06030>{number = 1, name = main}
这段代码是在主线程执行的, 在调试这段代码前,一直以为会死锁。我的理解是 dispatch_sync 同步操作会阻塞当前线程即主线程,同时队列将这个任务放到主线程执行(从输出看到),发生了双向阻塞为什么没有死锁。有请高手指证问题。
1
zwzmzd 2016-04-09 18:37:53 +08:00 via Android
无责任猜测, dispatch_sync 可以认为是“让出当前线程并等待完成”
|
3
zwzmzd 2016-04-09 19:11:08 +08:00
参考操作系统中阻塞型调用的实现,例如 socket 中的 recv 。此类调用在没有数据的情况下,相当于将控制权交还给系统调度器,而不是占有线程继续忙等待。
你的代码可以理解为下面的步骤: 1.将 block 注册为一个任务,并加入主线程“待执行”队列 2.注册完毕后,将自己加入主线程“待执行”队列,并让出当前线程(主线程) 3.调度器从主线程“待执行”队列中调度出刚刚注册的 GCD ,于是 NSLog(@"sync1:%@", [NSThread currentThread]);得到了执行。 4.GCD 执行完毕后,让出当前线程(主线程) 5.调度器从主线程“待执行”队列取出外层的任务,发现其等待条件已经得到满足,继续允许执行 |
4
Vernsu 2016-04-09 20:16:00 +08:00
你看,这样就死锁了。
dispatch_queue_t queue = dispatch_queue_create("serial1", DISPATCH_QUEUE_SERIAL); dispatch_sync(queue, ^{ dispatch_sync(queue, ^{ NSLog(@"sync1:%@", [NSThread currentThread]); }); NSLog(@"sync1:%@", [NSThread currentThread]); }); |
5
Vernsu 2016-04-09 20:19:41 +08:00
没有死锁的原因是 block 块中的任务加入了你所创建的串行队列,而不是主队列。所以不存在违背 FIFO 原则的问题。
以上都是我猜的。 |
6
zhangchioulin 2016-04-09 20:26:22 +08:00
mark 下班后到家了回复你
|
7
LINAICAI 2016-04-09 21:20:35 +08:00
死锁是两个线程之间竞争资源,但都拿不到访问资源的锁时造成的
|
8
Dean OP 自己查了下官方的文档 https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html 其中得出 GCD 出现死锁的结论: dispatch_sync 的当前执行队列与提交 block 执行的目标队列相同时将造成死锁。此处 Block 所在的队列与 dispatch_sync 在队列不同分别是自定义队列与主队列,至于 Block 输出的线程是主线程应该是线程池中的线程重用。
|
9
xi_lin 2016-04-09 23:29:52 +08:00
@Dean 推荐一个分析 libdispatch 的系列 http://blog.csdn.net/passerbysrs/article/details/18407959 这篇里提到 dispatch_sync 分发 block 到串行队列时会走到 queue.c 里的_dispatch_barrier_sync_f_slow 方法,里面会试图获取当前 thread 的 semaphore 。所以如果 dispatch_sync 执行时无法获取到信号量,就会一直死锁等下去了。
|
10
Alchemistxxd 2016-04-10 00:41:41 +08:00
queue != current Q, 所以 dispatch_sync 只是阻塞 queue ,并不会死锁。死锁的一个典型例子是 dispatch_sync(dispatch_get_main_queue(), ^{ });
|
11
codeisjobs 2016-04-10 00:50:14 +08:00 via iPhone
不管主队列还是其他队列,同步函数在手动创建的串行队列中是串行执行,不会发生死锁。只有同步函数在主队列中的时候,同时在主队列调用才会发生死锁。
|
12
codeisjobs 2016-04-10 00:57:10 +08:00 via iPhone 1
主队列中开了一个普通的串行队列来执行同步函数,并不会影响主队列,这是两个不同的队列。你要是在主队列中用主队列执行同步函数,你等我,我等你,才会死锁。
|
13
Loker 2016-04-10 21:19:25 +08:00
这样才会死锁
NSLog(@"Task 1"); dispatch_sync(dispatch_get_main_queue(), ^{ NSLog(@"Task 2"); }); NSLog(@"Task 3"); |
14
EdwardEan 2016-04-12 14:28:51 +08:00
不知道题主有没有读过 dispatch_sync 方法的这一段注释:
As an optimization, dispatch_sync() invokes the block on the current thread when possible. 如果明白了请试着考虑下下面一段代码的输出结果: |
15
EdwardEan 2016-04-12 14:29:43 +08:00
接上一段回复内容:
dispatch_sync(dispatch_get_global_queue(0, 0), ^{ [[NSOperationQueue mainQueue] addOperationWithBlock:^{ NSLog(@"First"); }]; [[NSOperationQueue currentQueue] addOperationWithBlock:^{ NSLog(@"Three"); }]; __block id observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"MyNotif" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { NSLog(@"Receive Notif"); [[NSNotificationCenter defaultCenter] removeObserver:observer]; }]; [[NSOperationQueue currentQueue] addOperationWithBlock:^{ NSLog(@"Forth"); }]; [[NSNotificationCenter defaultCenter] postNotificationName:@"MyNotif" object:self]; [[NSOperationQueue currentQueue] addOperationWithBlock:^{ NSLog(@"Five"); }]; }); |
16
lee0100317 2016-04-13 17:29:05 +08:00
请注意区分 Thread 和 dispatch_queue , dispatch_sync 阻塞的是 dispatch_queue ,而不是 Thread , Thread 只是 dispatch_queue 完成调度的载体而已。 dispatch_queue 存在的意义就是希望可以不再涉及 Thread 的内容,以及彻底抛弃锁。
|
17
Biscuits 2019-05-30 10:31:08 +08:00
@lee0100317 的确是这样, 他没搞清楚 dispatch_queue 和执行的 Thread 其实是分开的.
先回答为什么没有死锁问题 dispatch_sync 文档的 discussion 里面有这么一句 "Calling this function and targeting the current queue results in deadlock." 所以死锁问题有正确答案了. https://developer.apple.com/documentation/dispatch/1452870-dispatch_sync 然后解释为什么是主线程 还是👆的文档里面的 "As a performance optimization, this function executes blocks on the current thread whenever possible, with one obvious exception." 现在有 新建的 queue 和 main dispatch queue, 都是任务, Main_Thread 是(执行)资源. 在 Main_thread 调用 dispatch_sync, 把 block 任务加入 新 queue, 然后按照"this function executes blocks on the current thread whenever possible" 新 queue 拥有了主线程的执行资源, 进行执行, 然后返回继续 main dispatch queue . 所以 main dispatch queue 是持有了什么东西造成了死锁呢? |