Why is it necessary to call dispatch_group_leave the same number of times as dispatch_group_enter?

China☆狼群 提交于 2019-12-05 05:41:31
Kazuki Sakamoto

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

Compiled the Objective-C code with ARC.

$ clang -O0 -g -fobjc-arc a.m

Executed the program.

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

The program was crashed. If dispatch_group_leave(group) was called (enter and leave are all ballanced), there are no exceptions at all. Got the detail of the crash 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) 

The exception was occurred at _dispatch_semaphore_dispose. We can luckily read libdispatch source code at Apple OpenSource site. 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 forces calling signal/wait must be ballanced.

dispatch_semaphore_create manual:

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, calling dispatch_group_enter and dispatch_group_leave must be balanced as well.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!