いくつかの処理を実行し、CoreDataに保存するバックグラウンドスレッドがあります。私のアプリデリゲートapplicationShouldTerminate
では、バックグラウンドスレッドが作業を完了したときにリリースされるセマフォを待ちます。これは、作業の途中でスレッドを強制終了したり、一貫性のない状態のままにしたりしないようにするためです。
残念ながら、これによりデッドロックが発生します。バックグラウンドジョブの動作は次のとおりです。
_context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_context setParentContext:_parentContext];
[_context performBlock:
^{
// ... long-running task here ...
NSError * error;
[_context save:&error]; // deadlock here if main thread is waiting on semaphore
// ... release semaphore here ...
}];
バックグラウンドスレッドがまだ機能しているときにユーザーがアプリを終了すると、デッドロックが発生します。問題は、メインスレッド(または同等のもの)を[_context save:&error]
呼び出していることのようですdispatch_sync
が、メインスレッドはすでにこのスレッドがセマフォを解放するのを待っているため、ブロックを実行できません。
子コンテキストの保存はメインスレッドでブロックされているように見えるので、このパターン(子が完了してコンテキストを保存するのを待機しているメインスレッド)をどのように実現できますか?
メインスレッド:
#0 0x00007fff882e96c2 in semaphore_wait_trap ()
#1 0x00007fff876264c2 in _dispatch_semaphore_wait_slow ()
#2 0x00000001001157fb in +[IndxCore waitForBackgroundJobs] at /Users/mspong/dev/Indx/IndxCore/IndxCore/IndxCore.m:48
#3 0x00000001000040c6 in -[RHAppDelegate applicationShouldTerminate:] at /Users/mspong/dev/Indx/Indx/Indx/RHAppDelegate.m:324
#4 0x00007fff9071a48f in -[NSApplication _docController:shouldTerminate:] ()
#5 0x00007fff9071a39e in __91-[NSDocumentController(NSInternal) _closeAllDocumentsWithDelegate:shouldTerminateSelector:]_block_invoke_0 ()
#6 0x00007fff9071a23a in -[NSDocumentController(NSInternal) _closeAllDocumentsWithDelegate:shouldTerminateSelector:] ()
(snip)
#17 0x00007fff9048e656 in NSApplicationMain ()
#18 0x0000000100001e72 in main at /Users/mspong/dev/Indx/Indx/Indx/main.m:13
#19 0x00007fff8c4577e1 in start ()
背景スレッド:
#0 0x00007fff882e96c2 in semaphore_wait_trap ()
#1 0x00007fff87627c6e in _dispatch_thread_semaphore_wait ()
#2 0x00007fff87627ace in _dispatch_barrier_sync_f_slow ()
#3 0x00007fff8704a78c in _perform ()
#4 0x00007fff8704a5d2 in -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] ()
#5 0x00007fff8702c278 in -[NSManagedObjectContext save:] ()
#6 0x000000010011640d in __22-[Indexer updateIndex]_block_invoke_0 at /Users/mspong/dev/Indx/IndxCore/IndxCore/Indexer/Indexer.m:70
#7 0x00007fff87079b4f in developerSubmittedBlockToNSManagedObjectContextPerform_privateasync ()
#8 0x00007fff876230fa in _dispatch_client_callout ()
#9 0x00007fff876244c3 in _dispatch_queue_drain ()
#10 0x00007fff87624335 in _dispatch_queue_invoke ()
#11 0x00007fff87624207 in _dispatch_worker_thread2 ()
#12 0x00007fff88730ceb in _pthread_wqthread ()
#13 0x00007fff8871b1b1 in start_wqthread ()