2012-02-10 12 views
16

Apple's multithreading docs Nie wymieniaj NSIndexPath jako wątków safe, czy nie! Jako niezmienna klasa, generalnie spodziewam się, że będzie bezpieczna dla wątków.Czy wątki NSIndexPath są bezpieczne?

Wcześniej jestem pewien, że dokumentacja używana do stwierdzenia, że ​​instancje NSIndexPath zostały udostępnione i unikalne globalnie. Wygląda na to, że teraz zniknęło, co doprowadziło mnie do podejrzeń, że projekt został zmieniony na iOS5/Mac OS X 10.7.

Widzę sporo raportów o awariach klientów w systemie Mac OS X 10.6 (Snow Leopard), które wydają się zawieszające, próbując uzyskać dostęp do ścieżki indeksu. Zastanawiam się więc: czy rzeczywiste instancje są bezpieczne, ale czy logika wyrzucenia ich ze współdzielonej pamięci podręcznej nie jest? Czy ktokolwiek ma jakiś wgląd?

Oto przykład stos ślad BTW:

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 

Do mnie, że jest instancją NSIndexPath próbuje porównać się do dealokowane instancji.

+1

Co robisz z tymi ścieżkami indeksu i gdzie zdarza się awaria? Wielowątkowość błędów jest tajemnicza, awaria z 'NSIndexPath' niekoniecznie oznacza, że ​​problem występuje w' NSIndexPath'. – hamstergene

+0

Wykonuję żądanie pobierania, a następnie sortuję wyniki na podstawie ich metody '-indexPath'. Wewnętrznie, za każdym razem, gdy jest wywoływana, ta metoda tworzy ścieżkę indeksu, która reprezentuje położenie obiektu w drzewie. Podejrzewam, że jestem rozdawana we współdzielonych 'NSIndexPath's, które są następnie deallokowane wkrótce po innym wątku. –

+0

Skąd pochodzi nazwa NSIndexPath? Czy jest to własność sprowadzonego obiektu? –

Odpowiedz

4

Jak dotąd najlepsza odpowiedź mam to jak podejrzewam:

Począwszy od OS X 10.7 i iOS 5, NSIndexPath jest bezpieczne dla wątków. Wcześniej wystąpienia instancji są bezpieczne dla wątków, ponieważ są niezmienne, ale współużytkowane pobieranie istniejących instancji nie jest możliwe.

Do mojej metody, która zwraca indeks ścieżki na żądanie, zrobiłem to:

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

    return [[result retain] autorelease]; 
} 

Od realizacji tego ostatniego wiersza kodu, mieliśmy nie więcej raportów o awariach ze ścieżek indeksowych.

Ścieżki indeksu są tworzone przez -indexPathByAddingIndex: lub +indexPathWithIndex:.

Wyniki, które widzę, dają mi pewność, że (przed 10.7/iOS5) metody te zwracają istniejącą instancję NSIndexPath.Instancja ta nie jest w żaden sposób zachowywana przez bieżący wątek, więc wątek, który pierwszy stworzył instancję (główny w naszym przypadku) zwalnia ścieżkę (prawdopodobnie poprzez otwarcie puli autorelease) i pozostawiając nasz wątek roboczy zwisającym wskaźnikiem, który ulega awarii po użyciu, jak widać w pytaniu.

To wszystko jest trochę przerażające, ponieważ jeśli moja analiza jest poprawna, dodany przeze mnie taniec retain/autorelease zastępuje jeden wyścig z innym, mniej prawdopodobnym.

Przed 10.7/iOS5, mogę myśleć tylko o jednym prawdziwym obejściu: Ogranicz wszystkie tworzenie ścieżek indeksu do głównego wątku. To może być dość powolne, jeśli taki kod zostanie wywołany dużo, więc można by go poprawić - kosztem pamięci - poprzez utrzymywanie pewnego rodzaju własnej pamięci podręcznej instancji dla używanych wątków w tle. Jeśli pamięć podręczna zachowuje ścieżkę, oznacza to, że nie zostanie zwolniony przez główny wątek.

1

Apple nie wymienia listy NSIndexPath jako bezpiecznej dla wątków, ale mówią, że niezmienne klasy są ogólnie bezpieczne, a zmienne nie są generalnie bezpieczne. Ponieważ NSIndexPath jest niezmienna, można bezpiecznie założyć, że jest bezpieczna dla wątków.

Ale "wątek bezpieczny" nie oznacza, że ​​nie może powodować awarii przez zwolnienie go przez jeden wątek przed użyciem go na innym. Bezpieczny wątek oznacza po prostu, że jego metody mutatora zawierają blokowanie, aby zapobiec trzaskom z powodu jednoczesnego ustawiania właściwości dwóch wątków (dlatego klasy bez metod mutowania są ogólnie bezpieczne dla wątków, chociaż leniwy pobierający i współużytkowane instancje również mogą powodować problemy).

Wygląda na to, że Twój błąd jest bardziej prawdopodobny z powodu użycia puli autoreas lub innego mechanizmu, który powoduje, że Twój obiekt zostanie zwolniony w czasie poza twoją kontrolą. Powinieneś zapewne upewnić się, że wszystkie obiekty z dostępem do współbieżnego dostępu są przechowywane we właściwościach klas długowiecznych, dzięki czemu możesz kontrolować ich żywotność.

Tworzenie autorejestrowanego obiektu i uzyskiwanie dostępu do niego z innego wątku po usunięciu wszystkich silnych odniesień do niego jest niebezpieczną grą wyścigową, która może spowodować trudne do wykrycia awarie, niezależnie od tego, czy dany przedmiot to "wątek". bezpieczny".

+0

Tak, rozumiem różnorodność zagrożeń w wielowątkowym kodzie. Nie tworzę tych obiektów w jednym wątku i oczekuję, że będą żyły w innym wątku. Tworzę obiekty, prosząc 'NSIndexPath' o nich w wątku roboczym. Rozumiem, że w wersji 10.6 i wcześniejszych instancje 'NSIndexPath' są udostępniane globalnie. Podejrzewam, że globalna pamięć podręczna nie jest bezpieczna dla wątków, a nie poszczególnych instancji. –

+1

Możesz nadal czytać dokumenty iOS 4.3/OS 10.6 w Organizatorze w Xcode, jeśli pobierzesz starsze zestawy dokumentów i przeszukasz wszystkie zestawy dokumentów. Znalazłem linię, do której się odnosisz: "Obiekty NSIndexPath są unikalne i współdzielone.Jeśli ścieżka indeksu zawierająca określony indeks lub indeksy już istnieje, obiekt ten jest zwracany zamiast nowej instancji." I tak, wygląda na to, że został usunięty w najnowszych dokumentach, więc może masz rację, że NSIndexPath nie jest bezpieczny dla wątków w wersji 10.6. –

+0

Aha, zapomniałem, że możesz dostać się do starych dokumentów jeszcze! –

Powiązane problemy