1

我有一个并发类型为 NSMainQueueConcurrencyType 的 managedObjectContext

+ (NSManagedObjectContext *)managedObjectContextMainThread
{
    static NSManagedObjectContext *__managedObjectContext=nil;
    @synchronized(self)
    {
        if (__managedObjectContext != nil)
        {

        }
        else {
            NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
            if (coordinator != nil)
            {
                __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
                [__managedObjectContext setPersistentStoreCoordinator:coordinator];
            }
        }
    }
    return __managedObjectContext;
}

除非设置另一个 managedObjectContext.parent,否则永远不会在主线程之外访问主 managedObjectContext。因此 mainManagedObjectContext 是所有线程的父级。

现在当我运行程序时,有时它会陷入僵局。我暂停了程序,这就是我所看到的:

在此处输入图像描述

正如我们在图片中看到的,有 2 个线程似乎处于死锁状态。第一个是主线程。

它在@synchronize (self) 上死锁。合理的。

另一个线程死锁:

在此处输入图像描述

因此,当尝试更改保存 __managedObjectContext 的静态变量的持久存储时,它会锁定。

让我把代码再次重申一遍:

+ (NSManagedObjectContext *)managedObjectContextMainThread
{
    static NSManagedObjectContext *__managedObjectContext=nil;
    @synchronized(self) //Main thread deadlock here
    {
        if (__managedObjectContext != nil)
        {

        }
        else {
            NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
            if (coordinator != nil)
            {
                __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
                [__managedObjectContext setPersistentStoreCoordinator:coordinator]; //Secondary thread dead lock here
            }
        }
    }
    return __managedObjectContext;
}

我的问题是为什么在地球上[__managedObjectContext setPersistentStoreCoordinator:coordinator];

没有其他东西正在访问 __managedObjectContext。第二个线程(非主线程)试图将 __managedObjectContext 设置为父上下文。第一个线程只是在@synchronized 中愉快地等待。它什么也没做。

那么为什么会出现死锁以及如何解决呢?

哦,子 managedObjectContext 是在这里创建的:

@synchronized(self)
{
    if ([managedObjectContexts objectForKey:[self threadKey]] == nil ) {
        NSManagedObjectContext *threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        threadContext.parentContext = [self managedObjectContextMainThread];  //Stuck here. This goes straight to above function managedObjectContextMainThread where it stucks.
        threadContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
        [managedObjectContexts setObject:threadContext forKey:[self threadKey]];
    }
}
4

1 回答 1

2

问题是我试图在与主线程不同的线程上创建主托管对象上下文。

由于某种原因,它不起作用。

我仍然喜欢延迟加载。所以我需要做的就是确保主要的 managedObjectContext 是在

  1. 主线程
  2. 在创建任何其他 managedObjectContexts 之前。
  3. 我不想确保我的程序不会首先尝试访问其他 managedObjectContexts

所以这看起来像是 dispatch_sync 的工作。

然后我添加了这段代码:

    dispatch_sync(dispatch_get_main_queue(),^{
        [self managedObjectContextMainThread];//Access it once to make sure it's there
    });

在我创建所有后台子 managedObjectContexts 之前。这应该很快,因为一旦创建该函数将只返回静态变量。

+(NSManagedObjectContext *)managedObjectContext {


    NSThread *thread = [NSThread currentThread];
    //BadgerNewAppDelegate *delegate = [BNUtilitiesQuick appDelegate];
    //NSManagedObjectContext *moc = delegate.managedObjectContext;

    if ([thread isMainThread]) {
        //NSManagedObjectContext *moc = [self managedObjectContextMainThread];
        return [self managedObjectContextMainThread];
    }
    else{
        dispatch_sync(dispatch_get_main_queue(),^{
            [self managedObjectContextMainThread];//Access it once to make sure it's there
        });
    }

    // a key to cache the context for the given thread
    NSMutableDictionary *managedObjectContexts =[self thread].managedObjectContexts;

    @synchronized(self)
    {
        if ([managedObjectContexts objectForKey:[self threadKey]] == nil ) {
            NSManagedObjectContext *threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
            threadContext.parentContext = [self managedObjectContextMainThread];
            //threadContext.persistentStoreCoordinator= [self persistentStoreCoordinator]; //moc.persistentStoreCoordinator;//  [moc persistentStoreCoordinator];
            threadContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
            [managedObjectContexts setObject:threadContext forKey:[self threadKey]];
        }
    }


    return [managedObjectContexts objectForKey:[self threadKey]];
}
于 2012-10-12T00:47:51.227 回答