Сводка потокобезопасности

Это приложение описывает высокоуровневую потокобезопасность некоторых ключевых платформ в OS X и iOS. Информация в этом приложении подвержена изменениям.

Какао

Инструкции для использования Какао от многократных потоков включают следующее:

Потокобезопасность платформы основы

Существует неправильное представление, что платформа Основы ориентирована на многопотоковое исполнение, и платформа Набора Приложения не. К сожалению, это - обобщение брутто и несколько вводящий в заблуждение. Каждая платформа имеет области, которые ориентированы на многопотоковое исполнение и области, которые не ориентированы на многопотоковое исполнение. Следующие разделы описывают общую потокобезопасность платформы Основы.

Ориентированные на многопотоковое исполнение классы и функции

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

Небезопасные потоком классы

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

Обратите внимание на то, что несмотря на то, что NSSerializer, NSArchiver, NSCoder, и NSEnumerator объекты самостоятельно ориентированы на многопотоковое исполнение, они перечислены здесь, потому что не безопасно изменить объекты данных, обернутые ими, в то время как они используются. Например, в случае archiver, не безопасно изменить заархивированный граф объектов. Для перечислителя не безопасно ни для какого потока изменить перечислимый набор.

Основной поток только классы

Следующий класс должен использоваться только от основного потока приложения.

Непостоянный по сравнению с неизменным

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

Непостоянные объекты обычно не ориентированы на многопотоковое исполнение. Для использования непостоянных объектов в потоковом приложении приложение должно синхронизировать доступ к ним использующий блокировки. (Для получения дополнительной информации посмотрите Атомарные Операции). В целом, классы набора (например, NSMutableArray, NSMutableDictionary) когда мутации затронуты, не ориентированы на многопотоковое исполнение. Т.е. если один или несколько потоков изменяют тот же массив, проблемы могут произойти. Необходимо заблокировать вокруг спотов, где чтения и записи происходят для уверения потокобезопасности.

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

Повторная входимость

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

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

Инициализация класса

Система времени выполнения Objective C отправляет initialize обменивайтесь сообщениями к каждому объекту класса, прежде чем класс получит любые другие сообщения. Это дает классу шанс установить его среду выполнения, прежде чем он будет использоваться. В многопоточном приложении время выполнения гарантирует, что только один поток — поток, который, оказывается, отправляет первое сообщение в класс — выполняется initialize метод. В то время как первый поток находится все еще в, если второй поток пытается отправить сообщения в класс initialize метод, вторые блоки потока до initialize метод заканчивает выполняться. Между тем первый поток может продолжать вызывать другие методы на классе. initialize метод не должен полагаться на второй поток вызывающие методы класса; если это делает, два потока становятся заведенными в тупик.

Вследствие ошибки в версии 10.1.x OS X и ранее, поток мог отправить сообщения в класс, прежде чем другой поток закончил выполнять тот класс initialize метод. Поток мог тогда получить доступ к значениям, не полностью инициализированным, возможно разрушив приложение. При обнаружении с этой проблемой необходимо или представить блокировки для предотвращения доступа к значениям, пока они не инициализируются или вынуждают класс инициализировать себя прежде, чем стать многопоточными.

Пулы автовыпуска

Каждый поток поддерживает свой собственный штабель NSAutoreleasePool объекты. Какао ожидает там быть пулом автовыпуска, всегда доступным на штабеле текущего потока. Если пул не доступен, объекты не становятся выпущенными, и Вы пропускаете память. NSAutoreleasePool объект автоматически создается и уничтожается в основном потоке приложений на основе Набора Приложения, но вторичные потоки (и приложения Только для основы) должны создать свое собственное перед использованием Какао. Если Ваш поток долгосрочен и потенциально генерирует много автовыпущенных объектов, необходимо периодически уничтожать и создавать пулы автовыпуска (как Набор Приложения, делает на основном потоке); иначе, автовыпущенные объекты накапливаются, и Ваш объем потребляемой памяти растет. Если Ваш отдельный поток не использует Какао, Вы не должны создавать пул автовыпуска.

Выполненные циклы

Каждый поток имеет один и только один выполненный цикл. Каждый цикл выполнения, и следовательно каждый поток, однако, имеет свой собственный набор режимов ввода, определяющих, которые вводят источники, слушаются, когда выполняется цикл выполнения. Режимы ввода, определенные в одном цикле выполнения, не влияют на режимы ввода, определенные в другом цикле выполнения, даже при том, что у них может быть то же имя.

Цикл выполнения для основного потока автоматически выполняется, если Ваше приложение основывается на Наборе Приложения, но вторичные потоки (и приложения Только для основы) должны выполнить цикл выполнения сами. Если отдельный поток не вводит цикл выполнения, выходы потока, как только отдельный метод заканчивает выполняться.

Несмотря на некоторые исходящие появления, NSRunLoop класс не ориентирован на многопотоковое исполнение. Необходимо вызвать методы экземпляра этого класса только от потока, которому принадлежит он.

Потокобезопасность платформы набора приложения

Следующие разделы описывают общую потокобезопасность платформы Набора Приложения.

Небезопасные потоком классы

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

Основной поток только классы

Следующие классы должны использоваться только от основного потока приложения.

Ограничения окна

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

Можно создать модальное окно на вторичном потоке. В то время как основной поток выполняет модальный цикл, Набор Приложения блокирует вызывающий вторичный поток.

Ограничения обработки событий

Основной поток приложения ответственен за обработку событий. Основной поток является тем, блокированным в run метод NSApplication, обычно вызываемый в приложении main функция. В то время как Набор Приложения продолжает работать, если другие потоки включаются в конечном счете путь, операции могут произойти из последовательности. Например, если два различных потока отвечают на ключевые события, ключи могли бы быть получены не в порядке. Позволяя основному потоку обработать события, Вы достигаете более непротиворечивого пользовательского опыта. После того, как полученный, события могут быть диспетчеризированы вторичным потокам для последующей обработки при желании.

Можно вызвать postEvent:atStart: метод NSApplication от вторичного потока для регистрации события на очередь событий основного потока. Порядок не гарантируется относительно событий ввода данных пользователем, как бы то ни было. Основной поток приложения все еще ответственен за обработку событий в конечном счете очередь.

Рисование ограничений

Набор Приложения обычно ориентирован на многопотоковое исполнение при рисовании с его графическими функциями и классами, включая NSBezierPath и NSString классы. Подробные данные для использования определенных классов описаны в следующих разделах. Дополнительная информация о рисовании и потоках доступна в Руководстве по Рисованию Какао.

Ограничения NSView

NSView класс обычно не ориентирован на многопотоковое исполнение. Необходимо создать, уничтожить, изменить размеры, переместить и выполнить другие операции на NSView объекты только от основного потока приложения. Рисование от вторичных потоков ориентировано на многопотоковое исполнение, пока Вы заключаете в скобки вызовы получения с вызовами к lockFocusIfCanDraw и unlockFocus.

Если вторичный поток приложения хочет заставить части представления быть перерисованными на основном потоке, это не должно делать настолько использующих методов как display, setNeedsDisplay:, setNeedsDisplayInRect:, или setViewsNeedDisplay:. Вместо этого это должно отправить сообщение в основной поток или вызвать те методы с помощью performSelectorOnMainThread:withObject:waitUntilDone: метод вместо этого.

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

Ограничения NSGraphicsContext

NSGraphicsContext класс представляет контекст получения, предоставленный базовой графической системой. Каждый NSGraphicsContext экземпляр содержит свое собственное независимое состояние графики: система координат, отсечение, текущий шрифт, и т.д. Экземпляр класса автоматически создается на основном потоке для каждого NSWindow экземпляр. Если Вы делаете какое-либо получение от вторичного потока, нового экземпляра NSGraphicsContext создается в частности для того потока.

Если Вы делаете какое-либо получение от вторичного потока, необходимо сбросить вызовы получения вручную. Какао автоматически не обновляет представления с содержанием, нарисованным из вторичных потоков, таким образом, необходимо вызвать flushGraphics метод NSGraphicsContext когда Вы заканчиваете свое получение. Если Ваше приложение рисует содержание из основного потока только, Вы не должны сбрасывать свои вызовы получения.

Ограничения NSImage

Один поток может создать NSImage объект, нарисуйте к буферу изображения и выдайте его к основному потоку для рисования. Кэш основного изображения совместно используется среди всех потоков. Для получения дополнительной информации об изображениях и как кэширование работает, посмотрите, что Какао Рисует Руководство.

Базовая платформа данных

Базовая платформа Данных обычно поддерживает поточную обработку, несмотря на то, что существуют некоторые применяющиеся протесты использования. Для получения информации об этих протестах посмотрите Параллелизм с Базовыми Данными в Базовом Руководстве по программированию Данных.

Базовая основа

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

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

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