Является ли NSIndexPath потокобезопасным? - программирование
Подтвердить что ты не робот

Является ли NSIndexPath потокобезопасным?

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

Ранее я уверен, что документация, используемая для указания того, что экземпляры NSIndexPath были разделены и глобально уникальны. Это, кажется, исчезло сейчас, хотя, что привело меня к подозрению, что дизайн был пересмотрен для iOS5/Mac OS X 10.7.

Я вижу довольно много отчетов о сбоях от клиентов в Mac OS X 10.6 (Snow Leopard), которые, похоже, сбой, пытаясь получить доступ к указательному пути. Таким образом, я задаюсь вопросом: являются ли фактические потоки потоками безопасными, но что логика вытаскивания их из общего кэша не является? Кто-нибудь знает?

Здесь пример трассировки стека 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

Для меня это экземпляр NSIndexPath, пытающийся сравнить себя с деаллоцированным экземпляром.

4b9b3361

Ответ 1

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

Начиная с 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, который я добавил, просто заменяет одно состояние гонки другим, менее вероятным.

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

Ответ 2

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

Но "thread safe" не означает, что он не может вызывать сбои, выпуская один поток, прежде чем использовать его на другом. Потоковый сейф обычно означает, что его мутаторные методы содержат блокировку для предотвращения сбоев из-за одновременного задания свойств двух потоков (поэтому классы без методов мутаторов, как правило, являются потокобезопасными, хотя ленивые геттеры и общие экземпляры также могут вызывать проблемы).

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

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