Core Data 嵌套的托管对象上下文和频繁的死锁/冻结 [英] Core Data nested managed object contexts and frequent deadlocks / freezes

查看:16
本文介绍了Core Data 嵌套的托管对象上下文和频繁的死锁/冻结的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到的问题与此人在此处描述的问题几乎相同,但尚未得到解答:

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

问题来了:

我有一个带有 NSPrivateQueueConcurrencyType 的父 MOC 设置和一个持久存储协调器集,它有一个带有 NSMainQueueConcurrencyType 的子 MOC 设置.可以在私有 MOC 上完成大部分长期艰苦工作和保存的想法,从而使主线程免于阻塞 UI.不幸的是,我似乎遇到了几种导致死锁的情况.

如果子 MOC(在主线程上)正在使用 NSFetchedResultsController 执行提取,则父上下文会被发送一个 -executeFetchRequest:它会造成死锁.这两个操作都是在 performBlock: 的上下文中完成的:对于它们各自的 MOC,尽管文档似乎表明在没有 performBlock: 的情况下在主线程上使用主线程并发类型 MOC 是可以的.

似乎私有队列正在等待主线程上的子上下文已经锁定的 PSC 锁.看起来子上下文(同时持有 PSC 锁)正在尝试将 dispatch_sync 同步到父上下文,因此它们都在等待对方.

PriveQueue -> MainQueue 是受支持的配置吗?似乎大多数人仍然在主线程上拥有父上下文.

主线程如下所示:

<块引用>

>#0 0x960f6c5e 在 semaphore_wait_trap ()>#1 0x04956bb5 在_dispatch_thread_semaphore_wait()>#2 0x04955c8f 在_dispatch_barrier_sync_f_slow ()>#3 0x04955dea 在 dispatch_barrier_sync_f ()>#4 0x01797de5 在 _perform ()>#5 0x01798547 in -[NSManagedObjectContext(_NestedContextSupport) newValuesForObjectWithID:withContext:error:] ()>#6 0x0176416b 在_PFFaultHandlerLookupRow ()>#7 0x01763f97 in -[NSFaultHandler performFault:withContext:forIndex:] ()>#8 0x01763b75 在_PF_FulfillDeferredFault ()>#9 0x017639f2 在_sharedIMPL_pvfk_core ()>#10 0x017681a0 在 _pvfk_11 ()>#11 0x0001b322 in -[FBUser sectionName] at/Users/mlink/Code/x/x/FBUser.m:62>#12 0x011a8813 在_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 在 developerSubmittedBlockToNSManagedObjectContextPerform ()>#20 0x049554f0 在_dispatch_main_queue_callback_4CF ()>#21 0x01b3e833 在 __CFRunLoopRun()>#22 CFRunLoopRunSpecific () 中的 0x01b3ddb4>#23 CFRunLoopRunInMode 中的 0x01b3dccb ()>#24 0x023d6879 在 GSEventRunModal ()>#25 0x023d693e 在 GSEventRun ()>#26 UIApplicationMain () 中的 0x0089aa9b>#27 0x00002656 位于/Users/mlink/Code/x/x/main.mm:16

私有队列堆栈如下所示:

#0 0x960f8876 in __psynch_mutexwait()#1 pthread_mutex_lock () 中的 0x97e9e6af#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 在 developerSubmittedBlockToNSManagedObjectContextPerform_privateasync ()#10 0x04954ecf 在_dispatch_queue_drain ()#11 0x04954d28 在_dispatch_queue_invoke()#12 0x049544af 在_dispatch_worker_thread2 ()#13 0x97ea1b24 in _pthread_wqthread()#14 0x97ea36fe 在 start_wqthread ()

他还写道:

我开始认为问题出在 NSFetchedResultsController 上,当这些死锁发生时,它总是卡在 performFetch 上.大多数情况下,由于要求它的部分名称,它会试图在对象中出错.作为测试,我尝试重现 FRC 的功能并执行 executeFetchRequest: 然后遍历结果,询问每个对象的部分名称.这不会导致僵局.如果我离开 FRC 去做 performFetch:在我做我的测试之后它仍然会在那里死锁.我 99% 肯定 FRC 有嵌套上下文的同步问题.

问题:有人知道为什么会出现这个问题吗?你知道如何解决吗?这是一个错误吗?

解决方案

我刚看了此 SO 发布 其中,fabrice truillot de chambrier 建议目前不要使用嵌套上下文.他参考了文章 Core Data Growing Pains.

来自那篇文章:

<块引用>

NSFetchedResultsController 死锁

您永远不希望您的应用程序陷入僵局.和NSFetchedResultsController 和嵌套上下文,很容易做.使用上述相同的 UIManagedDocument 设置,执行使用时在私有队列上下文中获取请求带有主队列上下文的 NSFetchedResultsController 可能会僵局.如果您几乎同时开始两者,则会发生几乎 100% 的一致性.NSFetchedResultsController 可能是获取不应该的锁.这已被报告为已修复为即将发布的 iOS 版本.

radar://11861499 已在即将发布的版本中修复

这似乎准确描述了您的问题.

I have a problem that is almost identical to the problem described by this person here, but it hasn't get answered:

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

Here is the problem:

I have a parent MOC setup with NSPrivateQueueConcurrencyType and a persistent store coordinator set, it has a child MOC setup with NSMainQueueConcurrencyType. The idea being most of the long hard work and saves can be done on the private MOC freeing the main thread from blocking the UI. Unfortunately I seem to be running into a couple of situations that cause deadlocks.

If the child MOC (on the main thread) is performing a fetch with NSFetchedResultsController the parent context is sent an -executeFetchRequest: it can create a deadlock. Both operations are done within the context of a performBlock: for their respective MOCs although the docs seem to indicate that using a main thread concurrency type MOC on the main thread without performBlock: is fine.

It appears that the private queue is waiting on the PSCs lock which the child context on the main thread has already locked. It appears that the child context (while holding the PSCs lock) is trying to dispatch_sync to the parent context and thus they are both waiting for each other.

Is PriveQueue -> MainQueue a supported configuration? It seems most people still have the parent context on the main thread.

The main thread looks like this:

> #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

the private queue stack looks like this:

#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 ()

He also writes this:

I'm starting to think the problem is with NSFetchedResultsController which is always stuck at performFetch: when these deadlocks occur. Most of the time it will be stuck trying to fault in an object as a result of asking for it's section name. As a test I tried to reproduce what the FRC does and performed the executeFetchRequest: and then iterated through the results asking each object for it's section name. And this doesn't cause a deadlock. If I leave the FRC to do performFetch: after I do my test it will still deadlock there. I'm 99% sure that the FRC has a synchronization problem with nested contexts.

Question: Does anybody know why this problem occurs? Do you know how to solve it? Is this a bug?

解决方案

I just read this SO posting where fabrice truillot de chambrier recommends not to use nested contexts at present. He gives a reference to the article Core Data Growing Pains .

From that article:

NSFetchedResultsController deadlocks

You never want your application to deadlock. With NSFetchedResultsController and nested contexts, it’s pretty easy to do. Using the same UIManagedDocument setup described above, executing fetch requests in the private queue context while using NSFetchedResultsController with the main queue context will likely deadlock. If you start both at about the same time it happens with almost 100% consistency. NSFetchedResultsController is probably acquiring a lock that it shouldn’t be. This has been reported as fixed for an upcoming release of iOS.

radar://11861499 fixed in an upcoming release

This seems to describe exactly your issue.

这篇关于Core Data 嵌套的托管对象上下文和频繁的死锁/冻结的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆