Значит ли Atomic что-нибудь для синтезированного примитива?
В Android я мог безопасно получать доступ и изменять типы примитивов из разных потоков. Я использовал это для обмена данными между моим циклом отрисовки OpenGL и пользовательскими настройками, которые были изменены в основном потоке пользовательского интерфейса Android. Сохраняя каждый параметр в примитивном типе и делая каждый независимым от значений других, можно было потокобезопасно изменять все эти переменные без использования блокировок или ключевого слова синхронизации.
Это также верно в Objective-C? Я читал, что размещение атомарного в переменной по существу заставляет синтезированный метод получения и установки использовать блокировки, подобно использованию синхронизированных методов в Java. И я читал, что причина этого в том, что объект не изменяется частично, пока он читается другим потоком.
Но безопасны ли примитивные типы от частичной модификации, как в Java? Если это так, кажется, что я мог бы использовать мою прежнюю парадигму из Java для обмена данными между потоками. Но тогда ключевое слово atomic было бы бессмысленным для примитива, верно?
Я также читал, что более надежным и быстрым решением, чем использование атомарных переменных, является копирование объектов перед их использованием, если к ним обращаются из нескольких потоков. Но я не уверен, как это можно сделать. Разве неатомный объект не может быть изменен в процессе копирования, что приведет к повреждению копии?
3 ответа
Не гарантируется, что примитивные типы будут защищены от частичной модификации, потому что модификации в примитивных типах не гарантируются как атомарные в C, а Objective-C наследуется оттуда. C только гарантирует относительные точки последовательности, и нет необходимости, чтобы обработка между двумя точками последовательности была атомарной - практическое правило заключается в том, что каждое полное выражение является точкой последовательности.
На практике изменение примитивов часто представляет собой двухэтапный процесс; изменение вносится в регистр, а затем записывается в память. Маловероятно, что сама запись не будет атомарной, но также нет гарантии, когда это произойдет по сравнению с модификацией. Даже с volatile
квалификация, единственные гарантии предоставляются в терминах точек последовательности.
Apple предоставляет некоторые функции C для атомарных действий через OSAtomic.h, которые отображаются непосредственно на специализированные атомарные инструкции, которые процессоры предлагают для реализации механизмов параллелизма. Возможно, вы могли бы использовать один из них более напрямую, чем через мощный мьютекс.
Общие шаблоны в Objective-C:
- неизменяемые объекты и функциональные преобразования - есть и причины управления памятью, но отчасти поэтому
NSString
,NSArray
и т. д., особенно отличаются отNSMutableString
,NSMutableArray
, так далее; - очереди последовательной отправки, которые можно комбинировать с копированием-изменением-заменой путем копирования в очередь, перехода в другое место для изменения и последующего перехода в очередь для замены;
- такие
@synchronized
s,NSConditionLock
s или другие явные механизмы синхронизации, в зависимости от ситуации.
Основной поток сам по себе является очередью последовательной отправки, поэтому вы можете полностью игнорировать проблему параллелизма, если ограничитесь этим.
Атомно-синтезированные @properties невосприимчивы к одновременным частичным обновлениям. Методы доступа будут использовать блокировку при необходимости в этой архитектуре.
В общем, примитивные типы в C не обязательно безопасны в отношении одновременных частичных обновлений.
Я не верю, что вы можете частично изменить примитивный тип, это часть того, что делает их примитивными. Вы либо изменяете это, либо нет. В этом смысле я бы сказал, что они потокобезопасны.
Вы правы, когда говорите, что ключевое слово atomic будет бессмысленным для примитивного типа.
Кто-то уже попробовал это здесь: свойства Objective-c для примитивных типов