在我的dispatch_group代码中,我使用dispatch_group_wait来超时一组Web服务调用。 问题,似乎我需要计算调用dispatch_group_enter的次数,然后调用相同数量的剩余dispatch_group_leave,如果某些Web服务调用永远不会返回,导致dispatch_group_enter与dispatch_group_leave的数量不相等。为什么呢?
如果在超时发生并且触发dispatch_group_wait的情况下我不这样做,我已经看到崩溃发生了。一旦确保dispatch_group_enter / dispatch_group_leave与其通话计数匹配,崩溃就会消失。
dispatch_group_t group = dispatch_group_create();
for (...) {
dispatch_group_enter(group);
// Make backend call and upon return call dispatch_group_leave
[self backendCallWithCompletionHandler:^(id results) {
dispatch_group_leave(group);
}
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_group_wait(self.group, dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(self.timeoutInterval * NSEC_PER_SEC)));
dispatch_async(dispatch_get_main_queue(), ^{
//execute stuff on main thread
// call remaining dispatch_group_leave here if dispatch_group_enter and dispatch_group_leave count don't match?
});
});
答案 0 :(得分:20)
非常有趣。我在OS X 10.9.4上使用Xcode 5.1.1测试了以下简单代码。
/* test.m */
#include <dispatch/dispatch.h>
int main()
{
{
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
//dispatch_group_leave(group);
}
return 0;
}
使用ARC编译Objective-C代码。
$ clang -O0 -g -fobjc-arc a.m
执行程序。
$ ./a.out
illegal hardware instruction ./a.out
程序崩溃了。如果调用dispatch_group_leave(group)(进入和离开都是平衡的),则根本没有例外。使用lldb获取崩溃的详细信息。
$ lldb a.out
Current executable set to 'a.out' (x86_64).
(lldb) run
Process 73482 launched: 'a.out' (x86_64)
Process 73482 stopped
* thread #1: tid = 0x3808a1, 0x00007fff87125287 libdispatch.dylib`_dispatch_semaphore_dispose + 55, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
frame #0: 0x00007fff87125287 libdispatch.dylib`_dispatch_semaphore_dispose + 55
libdispatch.dylib`_dispatch_semaphore_dispose + 55:
-> 0x7fff87125287: ud2
0x7fff87125289: leaq 0x103b9(%rip), %rcx ; "BUG IN LIBDISPATCH: flawed group/semaphore logic"
0x7fff87125290: movq %rcx, -0x104f9b1f(%rip) ; gCRAnnotations + 8
0x7fff87125297: ud2
(lldb)
异常发生在_dispatch_semaphore_dispose。我们可以幸运地在Apple OpenSource网站上阅读libdispatch源代码。看看http://opensource.apple.com/source/libdispatch/libdispatch-339.92.1/src/semaphore.c
void
_dispatch_semaphore_dispose(dispatch_object_t dou)
{
dispatch_semaphore_t dsema = dou._dsema;
if (dsema->dsema_value < dsema->dsema_orig) {
DISPATCH_CLIENT_CRASH(
"Semaphore/group object deallocated while in use");
}
根据此源代码,dispatch_group使用dispatch_semaphore。并且dispatch_semaphore强制呼叫信号/等待必须平衡。
dispatch_semaphore_create手册:
CAVEATS
Unbalanced dispatch semaphores cannot be released. For a given sema-
phore, calls to dispatch_semaphore_signal() and dispatch_semaphore_wait()
must be balanced before dispatch_release() is called on it.
因此,调用dispatch_group_enter和dispatch_group_leave也必须保持平衡。