CoreDataを使用してマルチスレッドアプリケーションを作成しています。
- [NSManagedObjectContext lock]
標準のロックとしては機能しないという印象を受けています。概念実証として、Xcode3の「コマンドラインツール」テンプレートである「CoreData」フレーバーの後に作成されたサンプルを次に示します。
int main (int argc, const char * argv[])
{
objc_startCollectorThread();
NSManagedObjectContext *context = managedObjectContext();
[context lock];
[context lock];
NSLog(@"hello world! (context=%@)", context);
[context unlock];
[context unlock];
return 0;
}
Mac OS X 10.6.8または10.7.4で実行している場合、代わりにデッドロックが発生するはずです。次のログがあります。
2012-07-18 16:53:40.206 test[20004:a0b] hello world! (context=<NSManagedObjectContext: 0x20000df40>)
誰かが何が起こっているのか教えてもらえますか?
(コンテキストの代わりにNSLockのインスタンスを使用すると、デッドロックは予想どおりに発生します)
これは、 NSManagedObjectContextロックに関するAppleドキュメントからの抜粋です。
ロック
受信機のロックを取得しようとします。
- (void)lock
討論
このメソッドは、ロックを取得できるようになるまでスレッドの実行をブロックします。アプリケーションは、コードを実行する前にスレッドにロックの取得を要求することにより、コードのクリティカルセクションを保護します。クリティカルセクションが過ぎると、スレッドはロック解除を呼び出してロックを解放します。
このメッセージを管理対象オブジェクトコンテキストに送信すると、フレームワークがマルチスレッド環境でのトランザクションのスコープを理解するのに役立ちます。別のミューテックスオブジェクトを使用する代わりに、NSManagedObjectContextのNSLockingの実装を使用することをお勧めします。
管理対象オブジェクトコンテキストをロック(または正常にtryLock)する場合、ロック呼び出しが行われるスレッドは、ロック解除を呼び出すまで保持する必要があります。マルチスレッド環境でコンテキストを適切に保持しないと、デッドロックが発生します。
可用性MacOSXv10.4以降で利用できます。