#ios #objective-c #multithreading #thread-safety
#iOS #objective-c #многопоточность #потокобезопасность
Вопрос:
У меня есть a TableViewController
, который использует элемент с индексом N для ячейки табличного представления в строке N. Поскольку к индексу массива N можно получить доступ из разных потоков, я создал ThreadSafeMutableArray
класс, который выполняет чтение внутри a dispatch_sync
и запись под a dispatch_barrier_async
.
Предположим, я получаю объект с индексом N, скажем, используя Song *currSong = self.entries[N];
, а затем вношу изменения в свойства этого объекта. Правильно ли я понимаю, что мне нужно внести эти изменения потокобезопасным способом (потому что, например, tableview может запрашивать объект в ячейке N, и в то же время объект в ячейке N может быть обновлен, поскольку объект изображения, для которого он был получен из сети)? Если да, каков самый простой способ сделать мой пользовательский класс потокобезопасным?
Например: в этом ThreadSafeMutableArray
случае я смог добиться этого, переопределив следующие методы и используя dispatch_sync
и dispatch_barrier_async
в рамках новой реализации методов.
-(NSUInteger) count
-(id) objectAtIndex:(NSUInteger)index;
-(void) insertObject:(id)anObject atIndex:(NSUInteger)index;
-(void) removeObjectAtIndex:(NSUInteger)index;
-(void) addObject:(id)anObject;
-(void) removeLastObject;
-(void) replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
Комментарии:
1. Как вы думаете, почему ответ для вашего класса отличается от массива? Т.е. почему бы не использовать ту же модель синхронизации dispatch_(barrier_a)?
2. Спасибо @CRD. Единственная идея, которая приходит мне в голову, — создать свои собственные средства доступа для всех свойств и защитить их с помощью модели синхронизации dispatch_(barrier_a). Это лучший подход? Обычно я позволяю компилятору создавать мои средства доступа для моих свойств. Я слышал, что с аксессуарами могут возникнуть некоторые сложные проблемы. Есть ли какая-либо распространенная ошибка при создании средств доступа, о которой мне нужно беспокоиться?
Ответ №1:
Вам необходимо определить, что означает «потокобезопасный» в контексте вашего пользовательского класса / приложения. Возможно, вам просто нужна целостность данных, что означает, что ни один поток не видит недопустимое или частично сохраненное значение, например, подумайте об атомарных операциях чтения / записи; или вам может потребоваться целостность модели, например, где взаимосвязь нескольких элементов всегда правильная — как в вашем изменяемом массиве; или что-то между ними, например, подумайте обувеличение счетчика — это не так сложно, как поддерживать согласованность графика объектов, представляющих изменяемую структуру, но более сложно, чем простое атомарное чтение или запись. И т. Д. И т. Д. Безопасность потоков — большая тема!
Как только вы узнаете, что требуется вашему пользовательскому объекту, вы можете выбрать из атомарных свойств для простой целостности чтения / записи, блокировок для более сложных комбинаций, комбинаций синхронизации GCD, асинхронности, барьера, последовательных и параллельных очередей и т. Д.
Короче говоря, нет единого простого ответа. Изучите различные варианты, рассмотрите свои требования и выбирайте и выбирайте. Вы уже используете GCD для обеспечения потокобезопасности, это хорошо! Если вы придумали дизайн и у вас возникли проблемы с ним, вы всегда можете спросить ОБ ЭТОМ.
Возможно, вам покажется интересной эта статья о преимуществах или других преимуществах атомарных свойств. Автор, вероятно, немного суров к atomic, чтобы подчеркнуть свою точку зрения, но это, безусловно, стоит прочитать.
HTH
Ответ №2:
Самый простой способ добиться этого — создать единый метод доступа в вашем TableViewController
и использовать @syncrhonized
директиву для защиты доступа.
- (void)updateObjectAt:(NSUInteger)index {
@synchronized(itemArray) {
// Everything between the braces is protected by the @synchronized directive.
itemArray[index].update();
}
}
@synchornized
Директива налагает блокировку на массив, все, что находится внутри блока кода, может безопасно получать доступ к элементам массива и изменять их. Если каким-либо другим методам необходимо получить доступ к массиву, просто оберните его в @syncrhonized
блокировку массива.
Комментарии:
1. Но обновления могут быть несколькими, обновлять одно свойство, обновлять несколько свойств. Кроме того, мне нужно иметь возможность читать потокобезопасным способом.
2. Если все эти операции обновления находятся внутри
@syncrhonized
блока с блокировкой itemArray, они безопасны. Для чтения вы можете сделать то же самое, или, если вам нужно, чтобы клиент прочитал и удерживал элемент, вы можете вернуть копию элемента (из@synchronized
блока). Однако клиенту необходимо обновить себя.