2012-02-10 9 views
16

Apple's multithreading docsNSIndexPathをスレッドセーフとして登録しないでください!不変のクラスとして、私は一般にスレッドセーフであると期待しています。NSIndexPathはスレッドセーフですか?

以前は、NSIndexPathのインスタンスが共有され、グローバルに一意であることを示すために使用されたドキュメントは確かです。それが今消えてしまったようだが、iOS5/Mac OS X 10.7のデザインが改訂されたと思う。

Mac OS X 10.6(Snow Leopard)で、インデックスパスにアクセスしようとしてクラッシュしているように見えるクラッシュレポートが数多く表示されています。したがって、私は疑問に思う:実際のインスタンスはスレッドセーフですが、それらを共有キャッシュから引き出すためのロジックはありませんか?誰にも洞察はありますか?

はここところで例のスタックトレースです:

Dispatch queue: com.apple.root.default-priority 
0 libobjc.A.dylib 0x96513f29 _cache_getImp + 9 
1 libobjc.A.dylib 0x965158f0 class_respondsToSelector + 59 
2 com.apple.CoreFoundation 0x948bcb49 ___forwarding___ + 761 
3 com.apple.CoreFoundation 0x948bc7d2 _CF_forwarding_prep_0 + 50 
4 com.apple.Foundation 0x994b10c5 -[NSIndexPath compare:] + 93 
5 com.apple.Foundation 0x99415686 _NSCompareObject + 76 
6 com.apple.CoreFoundation 0x948af61c __CFSimpleMergeSort + 236 
7 com.apple.CoreFoundation 0x948af576 __CFSimpleMergeSort + 70 
8 com.apple.CoreFoundation 0x948af38c CFSortIndexes + 252 
9 com.apple.CoreFoundation 0x948fe80d CFMergeSortArray + 125 
10 com.apple.Foundation 0x994153d3 _sortedObjectsUsingDescriptors + 639 
11 com.apple.Foundation 0x994150d8 -[NSArray(NSKeyValueSorting) sortedArrayUsingDescriptors:] + 566 

私にとって、それは割り当て解除インスタンスに自分自身を比較しようとしているNSIndexPathインスタンスです。

+1

これらのインデックスパスはどうしますか?クラッシュはどこで発生しますか?マルチスレッドのバグは不思議で、 'NSIndexPath'でクラッシュしても必ずしも問題が' NSIndexPath'にあるわけではありません。 – hamstergene

+0

フェッチ要求を実行し、結果を '-indexPath'メソッドに基づいてソートします。内部的には、呼び出されるたびに、そのメソッドはツリー内のオブジェクトの位置を表すインデックスパスを作成します。私は、共有された 'NSIndexPath'を手渡していて、別のスレッドですぐに割り当てを解除されているのではないかと私は疑います。 –

+0

どこからNSIndexPathが発信されますか?フェッチされたオブジェクトのプロパティですか? –

答えて

4

今のところ最良の答えは次のとおりです。

OS X 10.7とiOS 5のとおり、NSIndexPathはスレッドセーフです。その前に、インスタンスはスレッド不変であるためスレッドセーフですが、既存のインスタンスの共有取得はできません。オンデマンドインデックスパスを返す私の方法に

、私はこれでした:コードの最後の行を導入して以来

- (NSIndexPath *)indexPath; 
{ 
    NSIndexPath *result = … // create the path as appropriate 

    return [[result retain] autorelease]; 
} 

を、私たちはインデックスのパスからこれ以上のクラッシュレポートを持っていたしました。

インデックスパスは、-indexPathByAddingIndex:または+indexPathWithIndex:で作成されます。

私が見ている結果は、(10.7/iOS5より前の)これらのメソッドは、既存のNSIndexPathインスタンスを返すことをかなり確信しています。そのインスタンスは現在のスレッドによって保持されていませんので、インスタンスを最初に作成したスレッド(ここではメイン)はパスを解放しています(自動解放プールをポップしている可能性があります)問題に見られるように、使用時にクラッシュします。

私の分析が正しいとすれば、私が追加したretain/autoreleaseのダンスは、単純に1つの競合状態を別の可能性の低い競合状態に置き換えているためです。

10.7/iOS5以前では、1つの真の回避策しか考えられません。すべてのインデックスパスの作成をメインスレッドに限定します。そのようなコードが大量に呼び出されるとかなり遅くなる可能性があるため、バックグラウンドスレッド用に独自のインスタンスキャッシュを使用することで、メモリを犠牲にして改善することができます。キャッシュがパスを保持している場合は、メインスレッドによって割り当て解除されないことがわかります。

1

Appleは特にNSIndexPathをスレッドセーフとしてリストアップしていませんが、不変のクラスは一般的に安全であり、変更可能なクラスは一般的にはそうではないと言います。 NSIndexPathは不変であるため、スレッドセーフであると想定することは安全です。

しかし、「スレッドセーフ」とは、別のスレッドで使用する前にスレッドによって解放されてもクラッシュを引き起こすことはできません。一般にスレッドセーフであるということは、2つのスレッドが同時にプロパティを設定することによる不具合を防ぐために、mutatorメソッドにロックが含まれていることを意味します(レイザゲッターや共有インスタンスでも問題が発生する可能性があります。

あなたのバグは、自動解放プールや、あなたのコントロールの外に一度にあなたのオブジェクトが解放されるような他のメカニズムを使用している可能性が高いようです。おそらく、並行してアクセスされるすべてのオブジェクトが寿命の長いクラスのプロパティに格納され、その寿命を制御できるようにする必要があります。

autoreleasedオブジェクトを作成し、そのオブジェクトへのすべての強力な参照を削除した後に別のスレッドからアクセスすると、問題のオブジェクトが「スレッド」であるかどうかにかかわらず、安全"。私は容疑者として、私が持っている

+0

はい、マルチスレッドコードのさまざまな危険性を理解しています。私はこれらのオブジェクトをあるスレッドで作成しておらず、それらが別のスレッドで生き続けることを期待していません。私はワーカースレッド上で 'NSIndexPath'を要求してオブジェクトを作成しています。 10.6以前では、 'NSIndexPath'インスタンスはグローバルに共有されています。このグローバルキャッシュは、個々のインスタンスではなくスレッドセーフではないと思われます。 –

+1

古いドキュメントセットをダウンロードしてすべてのドキュメントセットを検索すると、XcodeのオーガナイザでiOS 4.3/OS 10.6ドキュメントを読み込むことができます。 "NSIndexPathオブジェクトは一意であり、共有されています。指定されたインデックスを含むインデックスパスが既に存在する場合、新しいインスタンスの代わりにそのオブジェクトが返されます。"そして、はい、それは最新のドキュメントでは削除されているようですので、NSIndexPathが10.6でスレッドセーフではないことは間違いありません。 –

+0

ああ、私はあなたが古い文書にまだ行くことを忘れてしまった! –

関連する問題