1

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]];
    }
}
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 に答える