2013-06-13 11 views
6

W Objective C Używam instancji NSMutableArray z różnych wątków i używam @synchronized, aby zapewnić bezpieczny wątek. obecnie wszystkie moje dostęp do tej tablicy są chronione przy użyciu zsynchronizowanego bloku, a nawet metody objectAtIndex :. Niemniej jednak zastanawiam się, które metody wywołania naprawdę muszą być chronione przez @synchronized. czy muszę chronić dostęp do odczytu?Kolekcja NSMutableArray i @Synchronized blocks

Co by się stało, gdyby "ObjectAtIndex" nie był chroniony i wywołany w tym samym czasie co "removeObject"?

Jeśli wszystkie metody są chronione przez @ zsynchronizowane, co z wydajnością? (I'writing serwera gry tcp/udp i naprawdę nie chcę nadopiekuły tych tablic, jeśli zmniejszyłoby to perf lub wygenerowało blokady).

na przykład Przypuszczam, że metoda "containsObject:" wyliczy, aby znaleźć obiekt i że powinienem unikać konkurentnego wywołania "removeObject:" w innym wątku.

Być może dobrym rozwiązaniem byłoby mieć też różne zamki (do odczytu i zapisu) ...

Pomoc i sugestie są mile widziane!

Wielkie dzięki.

Proszę znaleźć przykładowy kod poniżej, aby zilustrować:

@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 

Odpowiedz

5

Tak, trzeba zsynchronizować czytać dostęp, aby zapobiec ich dzieje się równocześnie z mutacjami. Dostęp do odczytu można bezpiecznie uruchamiać jednocześnie z innymi dostępami do odczytu.

Jeśli masz wiele czytników, warto sprawdzić schemat blokowania odczytu i zapisu. Można użyć blokad odczytu i zapisu pthread (tj. pthread_rwlock_...()).

Można również użyć GCD w systemie OS X 10.7+ i iOS 5+ za pomocą procedur "barierowych". Utwórz prywatną kolejkę współbieżną. Prześlij wszystkie operacje odczytu w normalny sposób (np. dispatch_sync()). Prześlij do niej operacje mutacji za pomocą procedury zapory, takiej jak dispatch_barrier_async(). (Może być asynchroniczny, ponieważ zazwyczaj nie musisz wiedzieć, że mutacja została zakończona przed kontynuowaniem.Musisz tylko wiedzieć, że wszystkie odczyty przesłane po wysłaniu mutacji będą widoczne wyniki mutacji, a bariera to gwarantuje.)

Możesz dowiedzieć się więcej na ten temat, jeśli masz dostęp do WWDC 2011 session video for Session 210 - Mastering Grand Central Dispatch.

+0

Bardzo podoba mi się rozwiązanie GCD. Ponieważ używam wielu tablic zmiennych (i słownika), które chciałbym chronić, zastanawiam się, czy mogę stworzyć własne GCDMutableArray i GCDMutableDictionary, które zastąpią wszystkie metody i dodadzą dispatch_queue_t dla każdego wystąpienia tablicy lub słownika. Ale czy dobrym rozwiązaniem jest posiadanie 10 mutowalnych słowników z ich własnymi parametrami dispatch_queue? I utworzyć inną kolejkę w każdym przypadku? dispatch_queue_create przyjąć nazwę jako arg, jak wygenerować tę nazwę? Być może ten rodzaj chronionej tablicy i dyktatury został już napisany ... ale nie może niczego znaleźć. –

+0

Nie sądzę, że takie klasy są ogólnie przydatne. Niemal nigdy nie można osiągnąć bezpieczeństwa wątku, koncentrując się na klasach niskiego poziomu, takich jak pojemniki. Prawie na pewno musisz analizować swoje klasy na poziomie ich abstrakcji, aby * projektować * ich interfejsy, a nie tylko ich implementacje, dla bezpieczeństwa wątków. Powiedział, że kolejki wysyłki są tanie, a Apple zachęca do tworzenia jak najwięcej rozsądnych projektów. –

0

Musisz mieć świadomość, że to, co robisz, w rzeczywistości nie pomaga bardzo. Na przykład, jeśli twoja macierz ma dziesięć elementów i wywołujesz [myObject objectAtIndex: 9], podczas gdy inny wątek wywołuje [myObject removeObject: someObject], istnieje duże prawdopodobieństwo, że pierwsze wywołanie uzyskuje dostęp do elementu tablicy, który już nie istnieje i zgłasza wyjątek .

objectAtIndex nie przydaje się, jeśli inne wątki mogą usuwać lub wstawiać obiekty.