NSIndexPath потокобезопасен? - PullRequest
16 голосов
/ 10 февраля 2012

Многопоточные документы Apple не перечислять NSIndexPath как поточно-ориентированные или нет!Как неизменяемый класс, я, как правило, ожидаю, что он будет потокобезопасным.

Раньше я уверен, что документация использовала для утверждения, что экземпляры NSIndexPath являются общими и глобально уникальными.Похоже, что теперь это исчезло, что заставляет меня подозревать, что дизайн был пересмотрен для iOS 5 / 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, пытающийся сравнить себя с освобожденным экземпляром.

Ответы [ 2 ]

4 голосов
/ 25 февраля 2012

Пока лучший ответ, который у меня есть, как я подозреваю:

Начиная с 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. Этот экземпляр никак не сохраняется текущим потоком, поэтому поток, который первым создал экземпляр (в нашем случае, main), освобождает путь (вероятно, путем извлечения пула автоматического выпуска) и оставляет наш рабочий поток с висящим указателем, который вылетает при использовании, как видно из вопроса.

Это все немного страшно, потому что, если мой анализ верен, добавленный мною танец retain / autorelease просто заменяет одно состояние гонки другим, менее вероятным.

До 10.7 / iOS5 я мог думать только об одном верном обходном пути: ограничить все пути создания индексов основным потоком. Это может быть довольно медленным, если такой код часто вызывается, поэтому его можно улучшить - за счет памяти - за счет поддержки своего собственного кеша экземпляров для использования фоновыми потоками. Если кэш сохраняет путь, то вы знаете, что он не будет освобожден основным потоком.

1 голос
/ 21 февраля 2012

Apple специально не указывает NSIndexPath как потокобезопасный, но они говорят, что неизменяемые классы, как правило, безопасны, а изменяемые классы - нет.Поскольку NSIndexPath является неизменяемым, можно предположить, что он безопасен для потоков.

Но «потокобезопасность» не означает, что он не может вызывать сбои, будучи выпущенным одним потоком, прежде чем использовать его в другом.Потокобезопасность обычно означает, что его методы-мутаторы содержат блокировку для предотвращения сбоев из-за одновременной установки свойств двумя потоками (поэтому классы без методов-мутаторов, как правило, безопасны для потоков, хотя ленивые методы получения и общие экземпляры также могут вызывать проблемы).1004 * Похоже, что ваша ошибка более вероятна из-за использования пула автоматического выпуска или какого-либо другого механизма, который заставляет ваш объект освобождаться в то время, когда вы не можете его контролировать.Вы, вероятно, должны убедиться, что любые объекты, к которым одновременно обращаются, хранятся в свойствах долгоживущих классов, чтобы вы могли контролировать их срок службы.

Создание объекта с автоматическим выпуском и доступ к нему из другого потока после удаления всех надежных ссылокэто опасная гоночная игра, которая может вызывать трудно выявляемые сбои независимо от того, является ли рассматриваемый объект «потокобезопасным».

...