I have one managedObjectContext with concurency type of 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;
}
The main managedObjectContext is NEVER accessed outside of the main thread except when setting the other managedObjectContext.parent. So that mainManagedObjectContext is the parent for all threads.
Now when I run the program, sometimes it reach a deadlock. I pause the program and this is what I see:
As we see in the picture, there are 2 threads that seems to be in the deadlock. The first is the main thread.
It deadlock on @synchronize (self). Reasonable.
The other thread is deadlock on:
So it locks when trying to change the persistent store of the static variable that hold the __managedObjectContext.
Let me put the code again to reiterate:
+ (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;
}
My question is why in the earth the [__managedObjectContext setPersistentStoreCoordinator:coordinator];
NOTHING else is accessing __managedObjectContext. The second thread (the non main one) is trying to set the __managedObjectContext as the parent context. The first thread is just waiting happily in @synchronized. It doesn't do anything.
So why the deadlock and how to solve that?
Oh the child managedObjectContext is created here:
@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]];
}
}
The problem is I tried to create the main managed object context on a thread different than the main thread.
For some reason it doesn't work.
I still love lazy loading. So all I need to do is to ensure that the main managedObjectContext is created on
So that looks like a job for dispatch_sync.
I then added this code:
before I created all background child managedObjectContexts. That should be fast because once created the function will only return the static variable.