2013-06-13 10 views
6

Objective Cで私はさまざまなスレッドのNSMutableArrayインスタンスを使用していますが、スレッドセーフであるように@synchronizedを使用しています。現在この配列への私のすべてのアクセスは@synchronizedブロック、さらにはobjectAtIndex:メソッドで保護されています。それにもかかわらず、どのメソッドが本当に@synchronizedで保護される必要があるのでしょうか?読み取りアクセスを保護する必要はありますか?NSMutableArrayコレクションと@Synchronizedブロック

'ObjectAtIndex'が 'removeObject'と同時に保護されていない場合はどうなりますか?

すべてのメソッドが@synchronizedによって保護されている場合、パフォーマンスはどうですか? (私はtcp/udpゲームサーバーを作成し、perfを減らしたり、ロックを生成したりする場合、これらの配列をオーバープロテクトしたくありません。

たとえば、私は 'containsObject:'メソッドがオブジェクトを見つけるために列挙し、別のスレッドで 'removeObject:'へのconcurent呼び出しを避けるべきだと思います。

おそらく、良い解決策があまりにも違うロック持っている(読み取りのためにおよび書き込みアクセス)することです...

ヘルプや提案は大歓迎です!

ありがとうございます。

説明するために以下のサンプルコードを見つけてください:

@interface TestClass : NSObject 
{ 
    NSMutableArray * array; 
} 

@end 

@implementation TestClass 

- (id)init 
{ 
    self = [super init]; 
    if (self) 
    { 
     array = [NSMutableArray array]; 
    } 
    return self; 
} 

-(id)objectAtIndex:(NSUInteger)index 
{ 
    @synchronized(array) **// IS IT USEFUL OR NOT ??** 
    { 
     return [array objectAtIndex:index]; 
    } 
} 

-(void)removeObject:(id)object 
{ 
    @synchronized(array) 
    { 
     [array removeObject:object]; 
    } 
} 

-(void)compute 
{ 
    @synchronized(array) 
    { 
     for (id object in array) 
     { 
      [object compute]; 
     } 
    } 
} 

@end 

答えて

5

はい、あなたは読み取りが変異と同時に起こってからそれらを防ぐために、アクセス同期化する必要があります。ただし、読み取りアクセスは他の読み取りアクセスと同時に安全に実行できます。

複数のリーダーをお持ちの場合は、読み取りと書き込みのロック方式を検討する価値があります。 pthread読み書きロック(つまり、pthread_rwlock_...())を使用できます。

また、「バリア」ルーチンでOS X 10.7+およびiOS 5+でGCDを使用することもできます。プライベート同時キューを作成します。すべての読み取り操作を通常の方法で送信します(例:dispatch_sync())。 dispatch_barrier_async()などのバリアルーチンを使用して、突然変異操作をサブミットします。なぜなら、突然変異を提出した後に提出されたすべての読解は、突然変異の結果を見ることになり、その障壁によって保証されているということだけを知る必要があります。 )

WWDC 2011 session video for Session 210 - Mastering Grand Central Dispatchにアクセスできる場合、これについて詳しく知ることができます。

+0

私はGCDソリューションが本当に好きです。私が保護したい多くの可変配列(および辞書も)を使用しているので、私は自分自身のGCDMutableArrayとGCDMutableDictionaryを作成して、すべてのメソッドをオーバーライドし、arrayまたはdictionaryの各インスタンスに対してdispatch_queue_tを追加できるのだろうかと思います。しかし、独自のdispatch_queueで10個の可変ディクショナリを持つのは良い解決策ですか?そして、それぞれのインスタンスで異なるキューを作成するには? dispatch_queue_createは、この名前を生成するにはどのようにargとして名前を取るか?おそらく、この種の保護された配列と辞書は既に書かれていますが、何も見つけることはできません。 –

+0

私はそのようなクラスは一般的には有用ではないと思います。コンテナなどの低レベルクラスに集中してスレッドの安全性を実現することはほとんどありません。それらの抽象化のレベルでクラスを解析する必要があるのは、その実装だけでなく、スレッドの安全性のためのインタフェースを設計することです。つまり、ディスパッチキューは安価であり、Appleは合理的な設計が求められるほど多くのものを作成することを奨励しています。 –

0

あなたがしていることは、実際にはあまり役に立ちません。たとえば、配列に10個の要素があり、別のスレッドが[myObject removeObject:someObject]を呼び出すときに[myObject objectAtIndex:9]を呼び出すと、最初の呼び出しがもう存在しない配列要素にアクセスして例外がスローされる可能性があります。

objectAtIndexは、他のスレッドがオブジェクトを削除または挿入できる場合にはあまり役に立ちません。

関連する問題