NSMainQueueConcurrencyTypeの同時性タイプを持つ1つの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は、他のmanagedObjectContext.parentを設定する場合を除いて、メインスレッドの外部からアクセスされることはありません。そのため、mainManagedObjectContextはすべてのスレッドの親になります。
プログラムを実行すると、デッドロックに達することがあります。プログラムを一時停止すると、次のように表示されます。
写真でわかるように、デッドロック状態にあるように見える2つのスレッドがあります。1つ目はメインスレッドです。
@synchronize(自己)でデッドロックします。適正。
他のスレッドはデッドロックしています:
したがって、__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にアクセスしていません。2番目のスレッド(メイン以外のスレッド)は、__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]];
}
}