Core data NSManagedObjectContext-导致死锁的子上下文

Core data NSManagedObjectContext-导致死锁的子上下文,core-data,concurrency,deadlock,nsmanagedobjectcontext,Core Data,Concurrency,Deadlock,Nsmanagedobjectcontext,我在核心数据中有一个父-子-孙核心数据上下文设置,如下所示。每当我尝试在孙子上下文上执行一个fetch请求时,它都会导致线程死锁 - (NSManagedObjectContext *)defaultPrivateQueueContext { if (!_defaultPrivateQueueContext) { _defaultPrivateQueueContext = [[NSManagedObjectContext alloc] initWithConcurrenc

我在核心数据中有一个父-子-孙核心数据上下文设置,如下所示。每当我尝试在孙子上下文上执行一个fetch请求时,它都会导致线程死锁

- (NSManagedObjectContext *)defaultPrivateQueueContext
{
    if (!_defaultPrivateQueueContext) {
        _defaultPrivateQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        _defaultPrivateQueueContext.persistentStoreCoordinator = self.persistentStoreCoordinator;
    }
    return _defaultPrivateQueueContext;
}

- (NSManagedObjectContext *)mainThreadContext {
    if (!_mainThreadContext) {
        _mainThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        _mainThreadContext.parentContext = [self defaultPrivateQueueContext];
    }
    return _mainThreadContext;
}

+ (NSManagedObjectContext *)newPrivateQueueContext
{
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    context.parentContext = [[self sharedParliamentAPI] mainThreadContext];

    return context;
}
这是我的代码,它会导致死锁(在尝试执行提取请求时):


您的核心数据对象结构如下所示:

其中,您有一个
NSPrivateQueueConcurrencyType
上下文作为连接到持久存储协调器的根上下文,持久存储协调器有一个子
NSMainQueueConcurrencyType
上下文,后者又有一个
NSPrivateQueueConcurrencyType
上下文。很多在IntarWebs上写作的人都推荐这种结构

您的情况是,作为主队列上下文的专用队列上下文正变得繁忙,这导致其子级等待。因为主队列上下文正在使用主队列进行所有工作,所以发生这种情况时,它不一定会忙于执行核心数据工作(尽管这种情况仍有可能发生)。除了核心数据之外,主队列还做很多工作,所有这些事情最终都会在子队列需要与主队列上下文通信时影响子队列

此外,使用
NSMainQueueConcurrencyType
创建的上下文可以执行核心数据操作,而无需显式使用
performBlock:
performBlockAndWait:
。 例如,主队列上下文可以执行以下操作:

NSArray *results    = nil;
NSError *error      = nil;
results = [mainQueueContext executeFetchRequest:fetchRequest error:&error];
并且不需要这样做:

[mainQueueContext performBlock:^{
    NSArray *results    = nil;
    NSError *error      = nil;
    results = [mainQueueContext executeFetchRequest:fetchRequest error:&error];
}];
这里的区别在于,第一个没有
performBlock:
的示例将阻止主线程等待结果。第二种方法是使用
performBlock:
,它是异步的,不会阻塞-提取请求将被安排在队列上执行。显然,第一个示例可能会在任何子上下文中引起一些争用

如果您的配置有一个
NSMainQueueConcurrencyType
上下文,它是另一个
NSMainQueueConcurrencyType
上下文的子上下文,那么这将是。。。糟糕。在该配置中几乎可以保证死锁。好消息是,你没有这个问题


您可以将代码转换为使用
performBlock:
NSMainQueueConcurrencyType
上下文来缓解这部分问题。您还可以使用
NSPrivateQueueConcurrencyType
来代替您的主队列上下文-使用主队列上下文的理由不多

什么在使用
mainThreadContext
?使用该上下文的所有内容都是通过performBlock或performBlockAndWait来实现的吗?否则,可能会导致子级中出现死锁。执行此代码时,未使用mainThreadContext。是的,所有使用该上下文的操作都是通过performBlock实现的。如果您将根上下文设置为新子上下文的父上下文,消除了主线程上下文,是否仍然死锁?当我将新子上下文的父上下文设置为根上下文时,死锁消失。但是,这样做不会在进行更改时更新mainThreadContext(因为它是根上下文的一个单独的子级)。谢谢您的深入回答。我会试试看
[mainQueueContext performBlock:^{
    NSArray *results    = nil;
    NSError *error      = nil;
    results = [mainQueueContext executeFetchRequest:fetchRequest error:&error];
}];