In Core Data verschachtelte verwaltete Objektkontexte und häufige Deadlocks / Freezes

Ich habe ein Problem, das fast identisch mit dem Problem ist, das von dieser Person hier beschrieben wurde, aber es wurde nicht beantwortet:

http://www.cocoabuilder.com/archive/cocoa/312683-core-data-nested-managed-object-contexts-and-frequent-deadlocks.html#312683

Hier ist das Problem:

Ich habe ein übergeordnetes MOC-Setup mit NSPrivateQueueConcurrencyType und einen permanenten Speicherkoordinatorsatz. Es hat ein untergeordnetes MOC-Setup mit NSMainQueueConcurrencyType. Die Idee, die meiste harte Arbeit und das Speichern zu erledigen, kann auf dem privaten MOC gemacht werden, wodurch der Haupt-Thread von der Blockierung der Benutzeroberfläche befreit wird. Leider sehe ich mich mit einigen Situationen konfrontiert, die zu Deadlocks führen.

Wenn das untergeordnete MOC (im Hauptthread) einen Abruf mit NSFetchedResultsController ausführt, wird dem übergeordneten Kontext ein -executeFetchRequest gesendet: Es kann ein Deadlock erstellt werden. Beide Vorgänge werden im Kontext eines performBlock ausgeführt: für die jeweiligen MOCs, obwohl die Dokumente anscheinend darauf hinweisen, dass die Verwendung eines MOC des Typs "Parallelität Hauptthread" für den Hauptthread ohne performBlock: in Ordnung ist.

Es scheint, dass die private Warteschlange auf die PSC-Sperre wartet, die der untergeordnete Kontext im Hauptthread bereits gesperrt hat. Es scheint, dass der untergeordnete Kontext (während er die PSCs-Sperre hält) versucht, "dispatch_sync" mit dem übergeordneten Kontext zu senden, und daher warten beide aufeinander.

Ist PriveQueue -> MainQueue eine unterstützte Konfiguration? Es scheint, dass die meisten Menschen immer noch den übergeordneten Kontext im Haupt-Thread haben.

Der Haupt-Thread sieht so aus:

> #0    0x960f6c5e in semaphore_wait_trap ()
> #1    0x04956bb5 in _dispatch_thread_semaphore_wait ()
> #2    0x04955c8f in _dispatch_barrier_sync_f_slow ()
> #3    0x04955dea in dispatch_barrier_sync_f ()
> #4    0x01797de5 in _perform ()
> #5    0x01798547 in -[NSManagedObjectContext(_NestedContextSupport) newValuesForObjectWithID:withContext:error:] ()
> #6    0x0176416b in _PFFaultHandlerLookupRow ()
> #7    0x01763f97 in -[NSFaultHandler fulfillFault:withContext:forIndex:] ()
> #8    0x01763b75 in _PF_FulfillDeferredFault ()
> #9    0x017639f2 in _sharedIMPL_pvfk_core ()
> #10    0x017681a0 in _pvfk_11 ()
> #11    0x0001b322 in -[FBUser sectionName] at /Users/mlink/Code/x/x/FBUser.m:62
> #12    0x011a8813 in _NSGetUsingKeyValueGetter ()
> #13    0x017a0652 in -[NSManagedObject valueForKey:] ()
> #14    0x011ab8d5 in -[NSObject(NSKeyValueCoding) valueForKeyPath:] ()
> #15    0x01851f72 in -[NSFetchedResultsController(PrivateMethods) _sectionNameForObject:] ()
> #16    0x01853af6 in -[NSFetchedResultsController(PrivateMethods) _computeSectionInfo:error:] ()
> #17    0x01850ea6 in -[NSFetchedResultsController performFetch:] ()
> #18    0x0003a4fc in __62-[SYFriendsTableViewController updateFetchedResultsController]_block_invoke_0 ()
> #19    0x01797af3 in developerSubmittedBlockToNSManagedObjectContextPerform ()
> #20    0x049554f0 in _dispatch_main_queue_callback_4CF ()
> #21    0x01b3e833 in __CFRunLoopRun ()
> #22    0x01b3ddb4 in CFRunLoopRunSpecific ()
> #23    0x01b3dccb in CFRunLoopRunInMode ()
> #24    0x023d6879 in GSEventRunModal ()
> #25    0x023d693e in GSEventRun ()
> #26    0x0089aa9b in UIApplicationMain ()
> #27    0x00002656 in main at /Users/mlink/Code/x/x/main.mm:16

Der private Warteschlangenstapel sieht folgendermaßen aus:

#0    0x960f8876 in __psynch_mutexwait ()
#1    0x97e9e6af in pthread_mutex_lock ()
#2    0x0172ec22 in -[_PFLock lock] ()
#3    0x0172ebfa in -[NSPersistentStoreCoordinator lock] ()
#4    0x01746a8c in -[NSManagedObjectContext(_NSInternalAdditions) lockObjectStore] ()
#5    0x01745030 in -[NSManagedObjectContext executeFetchRequest:error:] ()
#6    0x0009d49f in -[NSManagedObjectContext(Additions) executeFetchRequest:] at /Users/mlink/Code/objc/C/C/NSManagedObjectContext+Additions.m:44
#7    0x0002177f in +[FBUser usersForFbids:inManagedObjectContext:] at /Users/mlink/Code/x/x/FBUser.m:435
#8    0x00021fc0 in __77+[FBUser updateUserFromGraphValues:inManagedObjectContext:completionHandler:]_block_invoke_0 at /Users/mlink/Code/x/x/FBUser.m:461
#9    0x0180f9f3 in developerSubmittedBlockToNSManagedObjectContextPerform_privateasync ()
#10    0x04954ecf in _dispatch_queue_drain ()
#11    0x04954d28 in _dispatch_queue_invoke ()
#12    0x049544af in _dispatch_worker_thread2 ()
#13    0x97ea1b24 in _pthread_wqthread ()
#14    0x97ea36fe in start_wqthread ()

Er schreibt auch Folgendes:

Ich fange an zu glauben, dass das Problem bei NSFetchedResultsController liegt, der immer bei performFetch steckt: wenn diese Deadlocks auftreten. Die meiste Zeit bleibt es hängen, einen Fehler in einem Objekt zu versuchen, weil nach dem Abschnittsnamen gefragt wird. Als Test habe ich versucht zu reproduzieren, was der FRC tut, und habe executeFetchRequest: ausgeführt und dann die Ergebnisse durchlaufen und jedes Objekt nach dem Abschnittsnamen gefragt. Und das verursacht keine Sackgasse. Wenn ich den FRC verlasse, um performFetch auszuführen, bleibt er dort nach dem Ausführen des Tests hängen. Ich bin zu 99% sicher, dass der FRC ein Synchronisationsproblem mit verschachtelten Kontexten hat.

Frage: Weiß jemand, warum dieses Problem auftritt? Wissen Sie, wie man es löst? Ist das ein Bug?

Antworten auf die Frage(7)

Ihre Antwort auf die Frage