在并发队列中使用dispatch_semaphore_t的死锁

时间:2012-10-30 22:45:48

标签: objective-c multithreading macos cocoa grand-central-dispatch

我正在开发一个使用GCD运行大量后台作业的MacOS X应用程序。后台作业使用CLucene索引文档,并在子上下文中访问Core Data。

这些作业都是在短时间内生成的(在使用DISPATCH_QUEUE_CONCURRENT创建的队列中使用dispatch_async),但只有4个一次完成实际工作。这是使用dispatch_semaphore_t完成的,通过在作业开始时等待它并在作业完成时释放它。

我在以下情况下看到一个非常奇怪,可靠的可重现的死锁:

  1. 后台作业仍在运行
  2. 用户将焦点切换到另一个应用程序,然后返回
  3. NSWindow显然在尝试在显示菜单栏时发送通知时陷入僵局。这是发生这种情况时主线程的堆栈跟踪:

    
    #0  0x00007fff870ae6c2 in semaphore_wait_trap ()
    #1  0x00007fff8b1bf486 in _dispatch_semaphore_wait_slow ()
    #2  0x00007fff8b69c12b in -[_NSDNXPCConnection sendMessage:waitForAck:] ()
    #3  0x00007fff8b57ced5 in _CFXNotificationPost ()
    #4  0x00007fff8b58bbf3 in CFNotificationCenterPostNotification ()
    #5  0x00007fff902ae174 in HIS_XPC_CFNotificationCenterPostNotification ()
    #6  0x00007fff8bd3612a in BroadcastToolboxMessage ()
    #7  0x00007fff8bd6d063 in MenuBarInstance::Show(MenuBarAnimationStyle, unsigned char, unsigned char, unsigned char) ()
    #8  0x00007fff8bd98144 in SetMenuBarObscured ()
    #9  0x00007fff8bd97e0f in HIApplication::HandleActivated(OpaqueEventRef*, unsigned char, OpaqueWindowPtr*) ()
    #10 0x00007fff8bd95407 in HIApplication::EventObserver(unsigned int, OpaqueEventRef*, void*) ()
    #11 0x00007fff8bd636e0 in _NotifyEventLoopObservers ()
    #12 0x00007fff898dc018 in -[NSWindow sendEvent:] ()
    #13 0x00007fff898d8744 in -[NSApplication sendEvent:] ()
    #14 0x00007fff897ee2fa in -[NSApplication run] ()
    #15 0x00007fff89792cb6 in NSApplicationMain ()
    #16 0x0000000100001e52 in main at /Users/mspong/dev/Indx/Indx/Indx/main.m:13
    #17 0x00007fff86b7b7e1 in start ()
    
    

    所有正在运行的后台作业都完成了他们的工作,但没有其他工作可以访问上述信号量。每个线程都停留在semaphore_wait_trap。

    我无法想象我可能会做什么(显然)导致无关的信号量(我的和苹果的)被卡住。任何人都可以就如何进一步调查提出一些建议吗?

1 个答案:

答案 0 :(得分:6)

你是否有可能遇到GCD并发队列线程限制(64个线程),然后做一些尝试在并发队列上工作的东西?这将导致整个框架中的随机死锁。

如果是这种情况,我唯一的建议是:永远不要阻塞并发队列。