2017-01-12 34 views
3

Вопросанити свойства типа элементарного значения - Objective C

Я работаю над проектом, где я обеспокоен потокобезопасностью свойств объекта. Я знаю, что когда свойство является объектом, например NSString, я могу столкнуться с ситуациями, когда несколько потоков одновременно читают и записывают. В этом случае вы можете получить поврежденное чтение, и приложение либо сбой, либо приведет к повреждению данных.

Мой вопрос касается свойств примитивного значения, таких как BOOL s или NSInteger s. Мне интересно, могу ли я попасть в аналогичную ситуацию, когда я читаю коррумпированное значение при чтении и записи из нескольких потоков (и приложение будет разбиваться)? В любом случае меня интересует, почему.

Разъяснение - 1/13/17

Я в основном заинтересован, если примитивный тип значение свойства по-разному восприимчивы к сбой из-за нескольких потоков к нему доступ в то же время, чем объект, такой как NSMutableString, пользовательский созданный объект и т. д. Кроме того, если есть разница при доступе к памяти в стеке против кучи относительно многопоточности.

Разъяснение - 12/1/17

Благодарим Вас @Rob за указание мне ответ здесь: stackoverflow.com/a/34386935/1271826! Этот ответ имеет отличный пример, который показывает, что в зависимости от типа архитектуры, в которой вы находитесь (32-разрядная версия с 64-разрядной версией), вы можете получить неопределенный результат при использовании свойства примитива.

Хотя это большой шаг к ответу на мой вопрос, я до сих пор удивляюсь две вещей:

  • Если есть разница многопоточности, когда доступ к свойству примитивного значения в стеке против кучи (как указано в моем предыдущем уточнение)?
  • Если вы ограничиваете работу программы на одной архитектуре, можете ли вы по-прежнему находиться в незащищенном состоянии, когда получаете доступ к первобытному значению свойства и почему?

Следует отметить, что в ответ на этот вопрос было много разговоров вокруг атомных против неатомических. Хотя это, как правило, важная концепция, этот вопрос имеет мало общего с предотвращением неопределенного многопотокового поведения с использованием модификатора атомного свойства или любого другого подхода к обеспечению безопасности потоков, такого как использование GCD.

+2

Использование атомных свойств позволяет избежать каких-либо ошибок чтения «поврежденных» значений. Но не обязательно избегать чтения «неправильных» значений. – rmaddy

+0

Правильно, я знаком с использованием атомных против неатомических, но читает «коррумпированное» значение для свойства примитивного типа значения? Если да, то почему? –

+0

Да, это возможно. Если вы запустите код на странице https://stackoverflow.com/a/34386935/1271826 на 32-битной цели, вы увидите поврежденные значения. – Rob

ответ

2

Если ваше свойство элемента примитивного значения равно atomic, то вы уверены, что он не может быть поврежден, потому что вы читаете его из одного потока при настройке его из другого (если вы используете только методы доступа и не взаимодействуете с поддержка ивара напрямую). Это целая цель atomic. И, как вы полагаете, это применимо только к фундаментальным типам данных (или объектам, которые являются неизменными и безстоящими). Но в этих узких случаях может оказаться полезным atomic.

Сказав это, это далеко не означает, что приложение является потокобезопасным. Это только гарантирует, что доступ к этому свойству является потокобезопасным. Но часто безопасность потоков должна рассматриваться в более широком контексте. (Я знаю, что вы заверяете нас, что это не так, но я готовлю это для будущих читателей, которые слишком быстро подскочат к выводу, что atomic является достаточным для обеспечения безопасности потоков.)

Например, если ваше NSInteger свойства «сколько элементов в этом объекте кэша», то не только должна что NSInteger иметь доступ synchronized, но она должна быть также синхронизирована в сочетании со всеми взаимодействиями с кэшем (например, задачи «добавить элемент в кеш» и «удалить элемент из кеша»). И в этих случаях, поскольку вы каким-либо образом синхронизируете все взаимодействие с этим более широким объектом (например, с GCD-очередью, блокировками, директивой @synchronized), в результате чего свойство NSIntegeratomic становится излишним и, следовательно, скромно менее эффективным.

Нижняя линия, в ограниченных количествах, atomic может обеспечить безопасность потоков для основных типов данных, но часто ее недостаточно при рассмотрении в более широком контексте.


Вы позже говорите, что вас не интересуют условия гонки. Для чего это стоит, Apple утверждает, что нет такой вещи, как доброкачественная раса. Смотрите видео WWDC 2016 Thread Sanitizer and Static Analysis (около 14:40 в него).

Во всяком случае, вы предлагаете вы просто обеспокоены ли значение может быть повреждено или будет ли приложение аварии:

Я интересно, если я могу попасть в подобную ситуацию, когда я прочитал коррумпированное значение при чтении и запись из нескольких потоков (и приложение выйдет из строя)?

Суть в том, что если вы читаете из одного потока во время мутации на другом, поведение просто неопределено. Это может измениться. Вам просто рекомендуется избегать этого сценария.

На практике это функция целевой архитектуры. Например, для 64-разрядного типа (например, long long) для 32-разрядной цели x86 вы можете легко получить поврежденное значение, где установлена ​​половина из 64-битного значения, а другая нет. (См. Например, https://stackoverflow.com/a/34386935/1271826.) Это приводит к просто нечувствительным, недопустимым числовым значениям при работе с примитивными типами. Для указателей на объекты это, очевидно, будет иметь катестографические последствия.

Но даже если вы находитесь в среде, где не возникает никаких проблем, это невероятно хрупкий подход, чтобы избежать синхронизации, чтобы обеспечить безопасность потока. Он может легко сломаться при запуске на новых, непредвиденных аппаратных архитектурах или скомпилированных в другой конфигурации. Я бы посоветовал вам посмотреть видео Thread Sanitizer and Static Analysis для получения дополнительной информации.

+0

Спасибо за ответ. В своем первом абзаце вы утверждаете, что изменяемые объекты, такие как NSMutableStrings, не могут быть повреждены при многопоточности? Если это так, они определенно могут. Вопрос, который я задал, сосредоточен вокруг примитивных типов значений, которые повреждаются многопотоком. Кроме того, вы можете объяснить, почему примитивы могут или не могут быть повреждены многопоточным. Я понимаю, что цель «атомная» - предотвращать коррупцию, но являются ли примитивы восприимчивыми к многопоточности так же, как к объектам? –

+0

Во-первых, мои объекты квалификации «неизменяемые и без гражданства», а не «изменчивые» (и технически даже это не совсем правильно, но вы получаете идею). Во-вторых, примитивные свойства атома не могут быть повреждены, потому что синтезированные методы доступа будут синхронизировать весь доступ (например,если вы сейчас читаете в одном потоке, запись на другом будет ждать, пока чтение не будет сделано, и наоборот). – Rob

+0

Наконец, я не могу примирить ваш последний вопрос: «примитивы восприимчивы к многопоточности так же, как к объектам?» с вашей уверенностью, что вы понимаете, что делает «атомный». «Atomic» синхронизирует все методы доступа к свойству, поэтому по определению это означает, что до тех пор, пока вы используете только методы доступа к свойству, вы не можете повредить примитивное свойство несколькими потоками. С объектами «атомный» просто обеспечивает целостность указателя на объект, но, очевидно, не сам объект, поэтому изменяемые объекты обычно являются проблемой многопоточного кода. – Rob

Смежные вопросы