核心数据:后台更新和主线程读取导致死锁

时间:2011-11-22 11:03:21

标签: objective-c core-data deadlock

我正在向用户显示包含一些数据的表格。一旦显示视图,我正在进行Web调用以查看是否有更新的数据(异步)。当服务调用返回时,我想更新我的核心数据和视图。

不幸的是,我经常会死锁,因为视图会读取与服务调用写入相同的数据。我该如何解决这个问题?

当模拟器冻结后暂停模拟器时,等待的线程在以下位置等待:

后台(更新)线程:(psynch_cvwait)

[mainContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
                              withObject:notification
                           waitUntilDone:YES];

主线程:(psynch_mutexwait)     执行filteredArrayUsingPredicate

非常感谢!

3 个答案:

答案 0 :(得分:8)

-mergeChangesFromContextDidSaveNotification:将阻止主线程。该调用将锁定NSManagedObjectContext个实例,同时更新主要上下文并传入更改。

在iOS 5之前的应用程序中,这通常被认为是不可避免的。您可以通过更频繁,更小的保存来最小化它,但它仍然会发生。

iOS 5之前的应用程序唯一的另一个选择是将主要上下文告诉-reset:,但这需要重新获取所有内容 - 另一个延迟。

答案 1 :(得分:2)

看起来主线程试图获取后台线程已经拥有的一些低级别锁定(反之亦然)。您是否在某处使用@synchronized来提供互斥?

无论如何,你的后台线程需要等待-mergeChangesFromContextDidSaveNotification:完成是否有任何理由?如果没有,请将NO作为最后一个参数传递。

答案 2 :(得分:0)

当我在主要和背景上下文(使用NSConfinementConcurrencyType)之间合并上下文更改(两种方式)时,我遇到了同样的问题(锁定psynch_cvwait)。问题是由订阅发送它的其他队列上的NSManagedObjectContextDidSaveNotification引起的:

[[NSNotificationCenter defaultCenter]
addObserverForName:NSManagedObjectContextDidSaveNotification
object:mainContext
queue:bgQueue
usingBlock:^(NSNotification * _Nonnull note) {
  // bgContext runs on bgQueue
  [bgContext mergeChangesFromContextDidSaveNotification:note];
}]

结果从未调用过块,并且psynch_cvwait()

上挂着主队列和后台队列

我通过不阻止mainContext的队列来修复它:

[[NSNotificationCenter defaultCenter]
addObserverForName:NSManagedObjectContextDidSaveNotification
object:mainContext
queue:nil
usingBlock:^(NSNotification * _Nonnull note) {
    [bgQueue addOperationWithBlock:^{
        [bgContext mergeChangesFromContextDidSaveNotification:note];
    }];
}]

但是,如果在将更改合并到主要上下文中时阻止后台队列,则似乎不会出现问题。