Why is it necessary to call dispatch_group_leave as many times as dispatch_group_enter?

In my dispatch_group code, I use dispatch_group_wait to disable a group of web service calls. The question, it seems, I will need to calculate how many times dispatch_group_enter is called, and then call the same number of the remaining dispatch_group_leave if some web service calls never return, causing an unequal number of dispatch_group_enter vs dispatch_group_leave. Why?

I have seen crashes if I do not do this in the event that a timeout occurs and runs dispatch_group_wait. The failure will disappear as soon as you verify that dispatch_group_enter / dispatch_group_leave matches their number of calls.

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? }); }); 
+6
source share
1 answer

Quite interesting. I tested the following simple code with Xcode 5.1.1 on OS X 10.9.4.

 /* 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; } 

Objective-C code compiled with ARC.

 $ clang -O0 -g -fobjc-arc am 

The program is running.

 $ ./a.out illegal hardware instruction ./a.out 

The program was broken. If dispatch_group_leave (group) was called (input and output are all balloted), there are no exceptions at all. Got accident details using 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) 

An exception occurred in _dispatch_semaphore_dispose. We are happy to read the libdispatch source code on the Apple OpenSource website. Take a look at 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"); } 

According to this source code, dispatch_group uses dispatch_semaphore. And dispatch_semaphore causes a signal / wait.

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. 

Thus, the calls to dispatch_group_enter and dispatch_group_leave must also be balanced.

+17
source

Source: https://habr.com/ru/post/974111/


All Articles