GCD を使用して、多数のバックグラウンド ジョブを実行する MacOS X アプリケーションを開発しています。バックグラウンド ジョブは、CLucene を使用してドキュメントのインデックスを作成し、子コンテキストで Core Data にアクセスします。
これらのジョブはすべて短い順序で生成されますが (DISPATCH_QUEUE_CONCURRENT で作成されたキューで dispatch_async を使用)、一度に実際の作業を行うのは 4 つだけです。これは、dispatch_semaphore_t を使用して、ジョブの開始時に待機し、ジョブの完了時に解放することで実現されます。
次の場合、非常に奇妙で確実に再現可能なデッドロックが発生します。
- バックグラウンド ジョブはまだ実行中です
- ユーザーがフォーカスを別のアプリケーションに切り替えてから戻す
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 でスタックします。
関係のないセマフォ (私のものと Apple のものの両方) をスタックさせるために (どうやら) 何ができるのか想像できません。これをさらに調査する方法について、誰かアドバイスをいただけますか?