如何解决偶尔发生的这种死锁?

时间:2012-10-11 09:24:05

标签: objective-c ios5 core-data nsmanagedobjectcontext xcode4.5

我有一个managedObjectContext,其concurency类型为NSMainQueueConcurrencyType

+ (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是所有线程的父级。

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

enter image description here

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

@synchronize(self)死锁。合理的。

另一个线程是死锁:

enter image description here

因此,当尝试更改包含__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]];
    }
}

1 个答案:

答案 0 :(得分:2)

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

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

我仍然喜欢懒加载。所以我需要做的就是确保在

上创建主要的managedObjectContext
  1. 主线程
  2. 在创建任何其他managedObjectContexts之前。
  3. 我不想确保我的程序不首先尝试访问其他的managedObjectContexts
  4. 所以这看起来像是dispatch_sync的工作。

    然后我添加了这段代码:

        dispatch_sync(dispatch_get_main_queue(),^{
            [self managedObjectContextMainThread];//Access it once to make sure it's there
        });
    
    在我创建所有后台子管理对象之前

    。这应该很快,因为一旦创建,该函数将只返回静态变量。

    +(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]];
    }